#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <ctype.h>
#include <unistd.h>
#include <string.h>
#include <sys/ioctl.h>
#include <time.h>
#include <math.h>
#include "xdma.h"
#include "device.h"
#include "key.h"
#include "manager.h"
#include "compute.h"
#include "card.h"



// 全局设备文件描述符
int device_fd[MAX_NUM];
const char *device_path[MAX_NUM] = {
    "/dev/decd1",
    "/dev/decd2",
    "/dev/decd3",
    "/dev/decd4",
    "/dev/decd5",
    "/dev/decd6",
    "/dev/decd7",
    "/dev/decd8",
    "/dev/decd9",
    "/dev/decd10",
};

nlist_t card_list;
card_t card[MAX_NUM];


int check_device_fd()
{
    for(int i = 0; i < card_num; i++) {
        if (device_fd[i] <= 0) {
            printf("open %s: failed\n", device_path[i]);
            return NFHE_DEVICE_NOTFOUND;
        }
    }
    return 0;
}


void Bn2Str(char *pbDest, unsigned char *pbSrc, int nLen)
{
	char ddl, ddh;
	int i;

	for (i = 0; i<nLen; i++)  
	{
		ddh = 48 + pbSrc[i] / 16;
		ddl = 48 + pbSrc[i] % 16;
		if (ddh > 57) ddh = ddh + 7;
		if (ddl > 57) ddl = ddl + 7;
		pbDest[(nLen * 2 - 1) - (i * 2 + 1)] = ddh;
		pbDest[(nLen * 2 - 1) - (i * 2)] = ddl;
	}
	pbDest[nLen * 2] = '\0';
}


void Str2Bn(unsigned char *bn, const char * a)
{
	unsigned char l = 0;
	unsigned int h = 0, i, j, k, c;
	unsigned int len = 0;

	len = (unsigned int)strlen((const char *)a);
	if (len % 2) {
		c = a[0];

		if ((c >= '0') && (c <= '9')) k = c - '0';
		else if ((c >= 'a') && (c <= 'f')) k = c - 'a' + 10;
		else if ((c >= 'A') && (c <= 'F')) k = c - 'A' + 10;
		else k = 0; /* paranoia */

		bn[(len - 1) / 2] = k;

		h = 1;

		j = 1;
	}
	else j = 0;

	for (i = j; i < len; i = i + 2) {

		c = a[i];

		if ((c >= '0') && (c <= '9')) k = c - '0';
		else if ((c >= 'a') && (c <= 'f')) k = c - 'a' + 10;
		else if ((c >= 'A') && (c <= 'F')) k = c - 'A' + 10;
		else k = 0; /* paranoia */

		l = k;

		c = a[i + 1];
		if ((c >= '0') && (c <= '9')) k = c - '0';
		else if ((c >= 'a') && (c <= 'f')) k = c - 'a' + 10;
		else if ((c >= 'A') && (c <= 'F')) k = c - 'A' + 10;
		else k = 0; /* paranoia */

		l = (l << 4) | k;

		bn[(len - 1) / 2 - (h++)] = l;
	}
}

void Str2Byte(unsigned char *bn, const char * a)
{
	int nCnt = (int)strlen(a);
	char b[] = "ss";
	for (int i = 0; i < nCnt / 2; i++)
	{
		b[0] = a[2 * i + 0]; b[1] = a[2 * i + 1];
		bn[i] = (unsigned char)strtoul(b, NULL, 16);
	}
}

void Byte2Str(char *pbDest, unsigned char *pbSrc, int nLen)
{
	char sz[3];

	pbDest[0] = '\0';
	for (int i = 0; i < nLen; i++)
	{
		sprintf(sz, "%02x", pbSrc[i]);
		strcat(pbDest, sz);
	}
}


void convertToLowercase(unsigned char* str) {
	while (*str != '\0') {
		if (islower(*str)) {
			*str = toupper(*str);
		}
		str++;
	}
}


void write_usr_reg(unsigned int fd, unsigned int addr, unsigned int data)
{
    Write_Usr_ioctl_ctx ctx;
    ctx.addr = addr;
    ctx.data = data;
    int result = ioctl(fd, IOCTL_WRITE_USR, &ctx);
    if (result < 0) {
        printf("IOCTL IOCTL_WRITE_USR: failed\n");
    }
}


// ********************************************* device.h *********************************************

int NFHE_OpenDevice()
{
    int rv;

    // get card number
    device_fd[0] = open(device_path[0], O_RDWR);
    rv = ioctl(device_fd[0], IOCTL_GETCARDNUM, &card_num);
    if(card_num == 0 || card_num > MAX_NUM) {
        printf("invalid card number\n");
        return -1;
    }

    for(int i = 0; i < card_num; i++) {
        device_fd[i] = 0;
    }

    nlist_init(&card_list);

    decd_ioctl_ctx data;
    data.inLen = 4 + 4;
    data.outLen = 8;
    int Command = SDF_OPENSESSION;
    int len = data.inLen < data.outLen ? data.outLen : data.inLen;
    data.pDataBuf = malloc(len + 1);
    
    for(int i = 0; i < card_num; i++) {
        device_fd[i] = open(device_path[i], O_RDWR);
        card_init(&card[i], device_fd[i]);
		nlist_insert(&card_list, &card[i].node);

        memset(data.pDataBuf, 0, data.inLen + 1);
        memcpy(data.pDataBuf, &Command, 4);
        rv = ioctl(device_fd[i], IOCTL_DECD, &data);
        if (rv < 0) {
            printf("IOCTL IOCTL_DECD: failed\n");
            rv = NFHE_IOCTL_ERROR;
            break;
        } else {
            memcpy(&rv, data.pDataBuf, 4);
            if (rv != 0) {  
                break;
            }
        }
    }

    if(data.pDataBuf) {
        free(data.pDataBuf);
    }

    if (rv != 0){
        printf("SDF_OPENSESSION: failed, ret: %x\n", rv);
        return rv;
    } else { 
        printf("NFHE_OpenDevice: success\n");
    }

    return rv;
}


int NFHE_CloseDevice()
{
    int rv;
    rv = check_device_fd();
    if(rv < 0) {
        return NFHE_DEVICE_NOTFOUND;
    }

    for (int i = 0; i < card_num; i++) {
		nlist_remove(&card_list);
        rv = close(device_fd[i]);
        if(rv < 0) {
            rv = NFHE_CLOSE_FAILED;
            break;
        }
	}
	nlist_free(&card_list);

    if(rv < 0){
        printf("NFHE_CloseDevice: failed\n");
        return NFHE_CLOSE_FAILED;
    }
    printf("NFHE_CloseDevice: success\n");

    return NFHE_OK;
}




// ********************************************* manager.h *********************************************

int FHEKmg_Restore_FactorySetting(unsigned char * pucAdmPassword, unsigned int uiAdmPasswordLength, char* primaryFactoryInformation, char* primaryFactoryDate)
{
    int rv;
    rv = check_device_fd();
    if(rv < 0) {
        return NFHE_DEVICE_NOTFOUND;
    }

    decd_ioctl_ctx data;
    data.inLen = 4 + 4 + uiAdmPasswordLength + 40 + 20;
    data.outLen = 8;
    int Command = KMG_RESTORE_FACTORYSETTING;
    int len = data.inLen < data.outLen ? data.outLen : data.inLen;
    data.pDataBuf = malloc(len + 1);

    for (int i = 0; i < card_num; i++) {
        memset(data.pDataBuf, 0, len + 1);
        memcpy(data.pDataBuf, &Command, 4);
        memcpy(data.pDataBuf + 4, &uiAdmPasswordLength, 4);
        memcpy(data.pDataBuf + 4 + 4, pucAdmPassword, uiAdmPasswordLength);
        memcpy(data.pDataBuf + 4 + 4 + uiAdmPasswordLength, primaryFactoryInformation, 40);
        memcpy(data.pDataBuf + 4 + 4 + uiAdmPasswordLength + 40, primaryFactoryDate, 20);

        rv = ioctl(device_fd[i], IOCTL_DECD, &data);
        if (rv < 0) {
            printf("IOCTL IOCTL_DECD: failed\n");
            rv = NFHE_IOCTL_ERROR;
            break;
        } else {
            memcpy(&rv, data.pDataBuf, 4);
            if (rv != 0){
                break;
            }
        }
    }

    if(data.pDataBuf) {
        free(data.pDataBuf);
    }

    if (rv != 0){
        printf("FHEKmg_Restore_FactorySetting: failed, rv: %x\n", rv);
        return rv;
    } else {
        printf("FHEKmg_Restore_FactorySetting: success\n");
    }
    
    return rv;
}


int FHEKmg_Get_DeviceInfo(
    unsigned char* pucAdmPassword, 
    unsigned int uiAdmPasswordLength,
    char* DeviceName,
    char* DeviceSerialNum,
    char* HardwareVersion,
    char* SoftwareVersion,
    char* primaryFactoryInformation,
    char* primaryFactoryDate
) {
    int rv;
    rv = check_device_fd();
    if(rv < 0) {
        return NFHE_DEVICE_NOTFOUND;
    }

    decd_ioctl_ctx data;
    data.inLen = 4 + 4 + uiAdmPasswordLength;
    data.outLen = 8 + 100;
    int Command = KMG_GET_DEVICEINFO;
    int len = data.inLen < data.outLen ? data.outLen : data.inLen;
    data.pDataBuf = malloc(len + 1);
    memset(data.pDataBuf, 0, len + 1);
	memcpy(data.pDataBuf, &Command, 4);
    memcpy(data.pDataBuf + 4, &uiAdmPasswordLength, 4);
    memcpy(data.pDataBuf + 4 + 4, pucAdmPassword, uiAdmPasswordLength);

    card_t* usedCard;
	usedCard = (card_t*)nlist_remove(&card_list);
    rv = ioctl(usedCard->fd, IOCTL_DECD, &data);
    nlist_insert(&card_list, &usedCard->node);

    if (rv < 0) {
        printf("IOCTL IOCTL_DECD: failed\n");
        rv = NFHE_IOCTL_ERROR;
    } else {
        memcpy(&rv, data.pDataBuf, 4);
    }

    if(rv == 0){
        DEVICEINFO *deviceInfo = data.pDataBuf + 8;
        memcpy(DeviceName, deviceInfo->DeviceName, 16);
        memcpy(DeviceSerialNum, deviceInfo->DeviceSerialNum, 16);
        memcpy(HardwareVersion, deviceInfo->HardwareVersion, 4);
        memcpy(SoftwareVersion, deviceInfo->SoftwareVersion, 4);
        memcpy(primaryFactoryInformation, deviceInfo->PrimaryFactoryInformation, 40);
        memcpy(primaryFactoryDate, deviceInfo->PrimaryFactoryDate, 20);
    }

    if(data.pDataBuf) {
        free(data.pDataBuf);
    }
    
    if (rv != 0){
        printf("FHEKmg_Get_DeviceInfo: failed, rv: %x\n", rv);
        return rv;
    } else {
        printf("FHEKmg_Get_DeviceInfo: success\n");
    }

    return NFHE_OK;
}


/**
 * userFactoryDate 存在 bug
*/
int FHEKmg_Init_UserInfo(
    unsigned char* pucAdmPassword,
    unsigned int uiAdmPasswordLength,
    char* userFactoryInformation,
    char* userFactoryDate
) {
    int rv;
    rv = check_device_fd();
    if(rv < 0) {
        return NFHE_DEVICE_NOTFOUND;
    }

    decd_ioctl_ctx data;
    data.inLen = 4 + 4 + uiAdmPasswordLength + 40 + 20;
    data.outLen = 8;
    int Command = KMG_INIT_USERINFO;
    int len = data.inLen < data.outLen ? data.outLen : data.inLen;
    data.pDataBuf = malloc(len + 1);

    for (int i = 0; i < card_num; i++) {
        memset(data.pDataBuf, 0, len + 1);
        memcpy(data.pDataBuf, &Command, 4);
        memcpy(data.pDataBuf + 4, &uiAdmPasswordLength, 4);
        memcpy(data.pDataBuf + 4 + 4, pucAdmPassword, uiAdmPasswordLength);
        memcpy(data.pDataBuf + 4 + 4 + uiAdmPasswordLength, userFactoryInformation, 40);
        memcpy(data.pDataBuf + 4 + 4 + uiAdmPasswordLength + 40, userFactoryDate, 20);

        rv = ioctl(device_fd[i], IOCTL_DECD, &data);
        if (rv < 0) {
            printf("IOCTL IOCTL_DECD: failed\n");
            rv = NFHE_IOCTL_ERROR;
            break;
        } else {
            memcpy(&rv, data.pDataBuf, 4);
            if (rv != 0){
                break;
            }
        }
    }

    if(data.pDataBuf) {
        free(data.pDataBuf);
    }

    if (rv != 0){
        printf("FHEKmg_Init_UserInfo: failed, rv: %x\n", rv);
        return rv;
    } else {
        printf("FHEKmg_Init_UserInfo: success\n");
    }

    return rv;
}


int FHEKmg_Get_UserInfo(
    unsigned char* pucAdmPassword,
    unsigned int uiAdmPasswordLength,
    char* userFactoryInformation,
    char* userFactoryDate
) {
    int rv;
    rv = check_device_fd();
    if(rv < 0) {
        return NFHE_DEVICE_NOTFOUND;
    }

    decd_ioctl_ctx data;
    data.inLen = 4 + 4 + uiAdmPasswordLength;
    data.outLen = 8 + 60;
    int Command = KMG_GET_USERINFO;
    int len = data.inLen < data.outLen ? data.outLen : data.inLen;
    data.pDataBuf = malloc(len + 1);
    memset(data.pDataBuf, 0, len + 1);
	memcpy(data.pDataBuf, &Command, 4);
    memcpy(data.pDataBuf + 4, &uiAdmPasswordLength, 4);
    memcpy(data.pDataBuf + 4 + 4, pucAdmPassword, uiAdmPasswordLength);

    card_t* usedCard;
    usedCard = (card_t*)nlist_remove(&card_list);
    rv = ioctl(usedCard->fd, IOCTL_DECD, &data);
    nlist_insert(&card_list, &usedCard->node);
    if (rv < 0) {
        printf("IOCTL IOCTL_DECD: failed\n");
        rv = NFHE_IOCTL_ERROR;
    } else {
        memcpy(&rv, data.pDataBuf, 4);
        if (rv != 0){
            printf("FHEKmg_Get_UserInfo: failed, rv: %x\n", rv);
        }
    }

    if(rv == 0){
        USERINFO *userInfo = data.pDataBuf + 8;
        memcpy(userFactoryInformation, userInfo->UserFactoryInformation, 40);
        memcpy(userFactoryDate, userInfo->UserFactoryDate, 20);
    }

    if(data.pDataBuf) {
        free(data.pDataBuf);
    }

    if (rv != 0){
        printf("FHEKmg_Get_DeviceInfo: failed, rv: %x\n", rv);
        return rv;
    } else {
        printf("FHEKmg_Get_DeviceInfo: success\n");
    }

    return rv;
}


int FHEKmg_Init_Device(unsigned char * pucAdmPassword, unsigned int uiAdmPasswordLength)
{
    int rv;
    rv = check_device_fd();
    if(rv < 0) {
        return NFHE_DEVICE_NOTFOUND;
    }

    decd_ioctl_ctx data;
    data.inLen = 4 + 4 + uiAdmPasswordLength;
    data.outLen = 8;
    int Command = KMG_INIT_DEVICE;
    int len = data.inLen < data.outLen ? data.outLen : data.inLen;
    data.pDataBuf = malloc(len + 1);

    for (int i = 0; i < card_num; i++) {
        memset(data.pDataBuf, 0, len + 1);
	    memcpy(data.pDataBuf, &Command, 4);
        memcpy(data.pDataBuf + 4, &uiAdmPasswordLength, 4);
        memcpy(data.pDataBuf + 4 + 4, pucAdmPassword, uiAdmPasswordLength);

        rv = ioctl(device_fd[i], IOCTL_DECD, &data);
        if (rv < 0) {
            printf("IOCTL IOCTL_DECD: failed\n");
            rv = NFHE_IOCTL_ERROR;
            break;
        } else {
            memcpy(&rv, data.pDataBuf, 4);
            if (rv != 0){
                break;
            }
        }
    }

    if(data.pDataBuf) {
        free(data.pDataBuf);
    }

    if (rv != 0){
        printf("FHEKmg_Init_Device: failed, rv: %x\n", rv);
        return rv;
    } else {
        printf("FHEKmg_Init_Device: success\n");
    }
    
    return NFHE_OK;
}


int FHEKmg_Verification(unsigned char * pucAdmPassword, unsigned int uiAdmPasswordLength)
{
    int rv;
    rv = check_device_fd();
    if(rv < 0) {
        return NFHE_DEVICE_NOTFOUND;
    }

    decd_ioctl_ctx data;
    data.inLen = 4 + 4 + uiAdmPasswordLength;
    data.outLen = 8;
    int Command = KMG_VERIFICATION;
    int len = data.inLen < data.outLen ? data.outLen : data.inLen;
    data.pDataBuf = malloc(len + 1);

    for (int i = 0; i < card_num; i++) {
        memset(data.pDataBuf, 0, len + 1);
        memcpy(data.pDataBuf, &Command, 4);
        memcpy(data.pDataBuf + 4, &uiAdmPasswordLength, 4);
        memcpy(data.pDataBuf + 4 + 4, pucAdmPassword, uiAdmPasswordLength);

        rv = ioctl(device_fd[i], IOCTL_DECD, &data);
        if (rv < 0) {
            printf("IOCTL IOCTL_DECD: failed\n");
            rv = NFHE_IOCTL_ERROR;
            break;
        } else {
            memcpy(&rv, data.pDataBuf, 4);
            if (rv != 0){
                break;
            }
        }
    }

    if(data.pDataBuf) {
        free(data.pDataBuf);
    }

    if (rv != 0){
        printf("FHEKmg_Verification: failed, rv: %x\n", rv);
        return rv;
    } else {
        printf("FHEKmg_Verification: success\n");
    }

    return NFHE_OK;
}


int FHEKmg_UnVerification()
{
    int rv;
    rv = check_device_fd();
    if(rv < 0) {
        return NFHE_DEVICE_NOTFOUND;
    }

    decd_ioctl_ctx data;
    data.inLen = 4 + 4;
    data.outLen = 8;
    int Command = KMG_UNVERIFICATION;
    int len = data.inLen < data.outLen ? data.outLen : data.inLen;
    data.pDataBuf = malloc(len + 1);

    for (int i = 0; i < card_num; i++) {
        memset(data.pDataBuf, 0, len + 1);
	    memcpy(data.pDataBuf, &Command, 4);

        rv = ioctl(device_fd[i], IOCTL_DECD, &data);
        if (rv < 0) {
            printf("IOCTL IOCTL_DECD: failed\n");
            rv = NFHE_IOCTL_ERROR;
            break;
        } else {
            memcpy(&rv, data.pDataBuf, 4);
            if (rv != 0){
                break;
            }
        }
    }

    if(data.pDataBuf) {
        free(data.pDataBuf);
    }

    if (rv != 0){
        printf("FHEKmg_UnVerification: failed, rv: %x\n", rv);
        return rv;
    } else {
        printf("FHEKmg_UnVerification: success\n");
    }

    return NFHE_OK;
}


int FHEKmg_Backup_DeviceKeyPair(unsigned char * pucAdmPassword, unsigned int uiAdmPasswordLength, char * device_keypair_str)
{
    int rv;
    rv = check_device_fd();
    if(rv < 0) {
        return NFHE_DEVICE_NOTFOUND;
    }
    
    decd_ioctl_ctx data;
    data.inLen = 4 + 4 + uiAdmPasswordLength;
    data.outLen = 8 + 256;
    int Command = KMG_BACKUP_DEVICEKEYPAIR;
    int len = data.inLen < data.outLen ? data.outLen : data.inLen;
    data.pDataBuf = malloc(len + 1);
    memset(data.pDataBuf, 0, len + 1);
	memcpy(data.pDataBuf, &Command, 4);
    memcpy(data.pDataBuf + 4, &uiAdmPasswordLength, 4);
    memcpy(data.pDataBuf + 4 + 4, pucAdmPassword, uiAdmPasswordLength);

    card_t* usedCard;
    usedCard = (card_t*)nlist_remove(&card_list);
    rv = ioctl(usedCard->fd, IOCTL_DECD, &data);
    nlist_insert(&card_list, &usedCard->node);

    if (rv < 0) {
        printf("IOCTL IOCTL_DECD: failed\n");
        rv = NFHE_IOCTL_ERROR;
    } else {
        memcpy(&rv, data.pDataBuf, 4);   
    }

    if(rv == 0) {
        unsigned char device_keypair_bin[256];
        memcpy(device_keypair_bin, data.pDataBuf + 8, 256);
        Bn2Str(device_keypair_str, device_keypair_bin, 256);
    }

    if(data.pDataBuf) {
        free(data.pDataBuf);
    }
    if (rv != 0){
        printf("FHEKmg_Backup_DeviceKeyPair: failed, rv: %x\n", rv);
        return rv;
    } else {
        printf("FHEKmg_Backup_DeviceKeyPair: success\n");
    }

    return NFHE_OK;
}


int FHEKmg_Restore_DeviceKeyPair(unsigned char* pucAdmPassword, unsigned int uiAdmPasswordLength, char* device_keypair_str)
{
    int rv;
    rv = check_device_fd();
    if(rv < 0) {
        return NFHE_DEVICE_NOTFOUND;
    }

    unsigned char device_keypair_bin[256];
	Str2Bn(device_keypair_bin, device_keypair_str);

    decd_ioctl_ctx data;
    data.inLen = 4 + 4 + 4 * ((uiAdmPasswordLength + 3) / 4) + 256;
    data.outLen = 8;
    int Command = KMG_RESTORE_DEVICEKEYPAIR;
    int len = data.inLen < data.outLen ? data.outLen : data.inLen;
    data.pDataBuf = malloc(len + 1);
    for (int i = 0; i < card_num; i++) {
        memset(data.pDataBuf, 0, len + 1);
        memcpy(data.pDataBuf, &Command, 4);
        memcpy(data.pDataBuf + 4, &uiAdmPasswordLength, 4);
        memcpy(data.pDataBuf + 4 + 4, pucAdmPassword, uiAdmPasswordLength);
        memcpy(data.pDataBuf + 4 + 4 + 4 * ((uiAdmPasswordLength + 3) / 4), device_keypair_bin, 256);

        int result = ioctl(device_fd[i], IOCTL_DECD, &data);
        if (result < 0) {
            printf("IOCTL IOCTL_DECD: failed\n");
            rv = NFHE_IOCTL_ERROR;
            break;
        } else {
            memcpy(&rv, data.pDataBuf, 4);
            if (rv != 0){
                break;
            }
        }
    }
    

    if(data.pDataBuf) {
        free(data.pDataBuf);
    }

    if (rv != 0){
        printf("FHEKmg_Restore_DeviceKeyPair: failed, rv: %x\n", rv);
        return rv;
    } else {
        printf("FHEKmg_Restore_DeviceKeyPair: success\n");
    }

    return NFHE_OK;
}


int FHEKmg_Backup_ProKey(unsigned char * pucAdmPassword,unsigned int uiAdmPasswordLength, char * prokey_str)
{
    int rv;
    rv = check_device_fd();
    if(rv < 0) {
        return NFHE_DEVICE_NOTFOUND;
    }
    
    decd_ioctl_ctx data;
    data.inLen = 4 + 4 + uiAdmPasswordLength;
    data.outLen = 8 + 128;
    int Command = KMG_BACKUP_PKEY;
    int len = data.inLen < data.outLen ? data.outLen : data.inLen;
    data.pDataBuf = malloc(len + 1);
    memset(data.pDataBuf, 0, len + 1);
	memcpy(data.pDataBuf, &Command, 4);
    memcpy(data.pDataBuf + 4, &uiAdmPasswordLength, 4);
    memcpy(data.pDataBuf + 4 + 4, pucAdmPassword, uiAdmPasswordLength);

    card_t* usedCard;
    usedCard = (card_t*)nlist_remove(&card_list);
    rv = ioctl(usedCard->fd, IOCTL_DECD, &data);
    nlist_insert(&card_list, &usedCard->node);
    if (rv < 0) {
        printf("IOCTL IOCTL_DECD: failed\n");
        rv = NFHE_IOCTL_ERROR;
    } else {
        memcpy(&rv, data.pDataBuf, 4);
    }

    if(rv == 0){
        unsigned char prokey_bin[128];
        memset(prokey_bin, 0, 128);
        memcpy(prokey_bin, data.pDataBuf + 8, 128);
        Bn2Str(prokey_str, prokey_bin, PROTECT_KEY_CRYPTO_LENGTH);
    }

    if(data.pDataBuf) {
        free(data.pDataBuf);
    }

    if (rv != 0){
        printf("FHEKmg_Backup_ProKey: failed, rv: %x\n", rv);
        return rv;
    } else {
        printf("FHEKmg_Backup_ProKey: success\n");
    }

    return NFHE_OK;
}


int FHEKmg_Restore_ProKey(unsigned char * pucAdmPassword, unsigned int uiAdmPasswordLength, char * prokey_str)
{
    int rv;
    rv = check_device_fd();
    if(rv < 0) {
        return NFHE_DEVICE_NOTFOUND;
    }

    unsigned char prokey_bin[128];
	Str2Bn(prokey_bin, prokey_str);

    decd_ioctl_ctx data;
    data.inLen = 4 + 4 + 4 * ((uiAdmPasswordLength + 3) / 4) + 128;
    data.outLen = 8;
    int Command = KMG_RESTORE_PKEY;
    int len = data.inLen < data.outLen ? data.outLen : data.inLen;
    data.pDataBuf = malloc(len + 1);

    for (int i = 0; i < card_num; i++) {
        memset(data.pDataBuf, 0, len + 1);
        memcpy(data.pDataBuf, &Command, 4);
        memcpy(data.pDataBuf + 4, &uiAdmPasswordLength, 4);
        memcpy(data.pDataBuf + 4 + 4, pucAdmPassword, uiAdmPasswordLength);
        memcpy(data.pDataBuf + 4 + 4 + 4 * ((uiAdmPasswordLength + 3) / 4), prokey_bin, 128);

        rv = ioctl(device_fd[i], IOCTL_DECD, &data);
        if (rv < 0) {
            printf("IOCTL IOCTL_DECD: failed\n");
            rv = NFHE_IOCTL_ERROR;
            break;
        } else {
            memcpy(&rv, data.pDataBuf, 4);
            if (rv != 0){
                break;
            }
        }
    }

    if(data.pDataBuf) {
        free(data.pDataBuf);
    }

    if (rv != 0){
        printf("FHEKmg_Restore_ProKey: failed, rv: %x\n", rv);
        return rv;
    } else {
        printf("FHEKmg_Restore_ProKey: success\n");
    }

    return NFHE_OK;
}



int FHEKmg_Update_KeyMngerPassword(unsigned char* pucOldPassword, unsigned int uiOldPwdLength, unsigned char* pucNewPassword, unsigned int uiNewPwdLength) {
    int rv;
    rv = check_device_fd();
    if(rv < 0) {
        return NFHE_DEVICE_NOTFOUND;
    }

    if(uiOldPwdLength != 16 || uiNewPwdLength != 16) {
        return NFHE_ERROR_LEN;
    }

    decd_ioctl_ctx data;
    data.inLen = 4 + 4 + 4 + 4 * ((uiOldPwdLength + 3)/4) + uiNewPwdLength;
    data.outLen = 8;
    int Command = KMG_UPDATE_KEYMNGERPASSWORD;
    int len = data.inLen < data.outLen ? data.outLen : data.inLen;
    data.pDataBuf = malloc(len + 1);

    for (int i = 0; i < card_num; i++) {
        memset(data.pDataBuf, 0, len + 1);
        memcpy(data.pDataBuf, &Command, 4);
        memcpy(data.pDataBuf + 4, &uiOldPwdLength, 4);
        memcpy(data.pDataBuf + 4 + 4, pucOldPassword, uiOldPwdLength);
        memcpy(data.pDataBuf + 4 + 4 + 4 * ((uiOldPwdLength + 3) / 4), &uiNewPwdLength, 4);
        memcpy(data.pDataBuf + 4 + 4 + 4 + 4 * ((uiOldPwdLength + 3) / 4), pucNewPassword, uiNewPwdLength);

        rv = ioctl(device_fd[i], IOCTL_DECD, &data);
        if (rv < 0) {
            printf("IOCTL IOCTL_DECD: failed\n");
            rv = NFHE_IOCTL_ERROR;
            break;
        } else {
            memcpy(&rv, data.pDataBuf, 4);
            if (rv != 0){
                break;
            }
        }
    }

    if(data.pDataBuf) {
        free(data.pDataBuf);
    }

    if (rv != 0){
        printf("FHEKmg_Update_KeyMngerPassword: failed, rv: %x\n", rv);
        return rv;
    } else {
        printf("FHEKmg_Update_KeyMngerPassword: success\n");
    }

    return NFHE_OK;
}




// ********************************************* key.h *********************************************
int FHEKmg_Create_Kekey(unsigned int uiKeyIndex)
{
    int rv;
    rv = check_device_fd();
    if(rv < 0) {
        return NFHE_DEVICE_NOTFOUND;
    }

    decd_ioctl_ctx data;
    data.inLen = 4 + 4;
    data.outLen = 8;
    int Command = KMG_CREATE_KEKEY;
    int len = data.inLen < data.outLen ? data.outLen : data.inLen;
    data.pDataBuf = malloc(len + 1);

    for (int i = 0; i < card_num; i++) {
        memset(data.pDataBuf, 0, len + 1);
        memcpy(data.pDataBuf, &Command, 4);
        memcpy(data.pDataBuf + 4, &uiKeyIndex, 4);

        rv = ioctl(device_fd[i], IOCTL_DECD, &data);
        if (rv < 0) {
            printf("IOCTL IOCTL_DECD: failed\n");
            rv = NFHE_IOCTL_ERROR;
            break;
        } else {
            memcpy(&rv, data.pDataBuf, 4);
            if (rv != 0){
                break;
            }
        }
    }

    if(data.pDataBuf) {
        free(data.pDataBuf);
    }

    if (rv != 0){
        printf("FHEKmg_Create_Kekey: failed, rv: %x\n", rv);
        return rv;
    } else {
        printf("FHEKmg_Create_Kekey: success\n");
    }

    return NFHE_OK;
}


int FHEKmg_Backup_KeKey(unsigned int uiKeyIndex, char * kekey_str)
{
    int rv;
    rv = check_device_fd();
    if(rv < 0) {
        return NFHE_DEVICE_NOTFOUND;
    }
    
    decd_ioctl_ctx data;
    data.inLen = 4 + 4;
    data.outLen = 8 + 16;
    int Command = KMG_BACKUP_KEKEY;
    int len = data.inLen < data.outLen ? data.outLen : data.inLen;
    data.pDataBuf = malloc(len + 1);
    memset(data.pDataBuf, 0, len + 1);
	memcpy(data.pDataBuf, &Command, 4);
    memcpy(data.pDataBuf + 4, &uiKeyIndex, 4);

    card_t* usedCard;
    usedCard = (card_t*)nlist_remove(&card_list);
    rv = ioctl(usedCard->fd, IOCTL_DECD, &data);
    nlist_insert(&card_list, &usedCard->node);

    if (rv < 0) {
        printf("IOCTL IOCTL_DECD: failed\n");
        rv = NFHE_IOCTL_ERROR;
    } else {
        memcpy(&rv, data.pDataBuf, 4);
    }

    if(rv == 0){
        unsigned char kekey_bin[16];
        memcpy(kekey_bin, data.pDataBuf + 8, 16);
        Bn2Str(kekey_str, kekey_bin, 16);
    }

    if(data.pDataBuf) {
        free(data.pDataBuf);
    }

    if (rv != 0){
        printf("FHEKmg_Backup_KeKey: failed, rv: %x\n", rv);
        return rv;
    } else {  
        printf("FHEKmg_Backup_KeKey: success\n");
    }

    return NFHE_OK;
}


int FHEKmg_Restore_KeKey(unsigned int uiKeyIndex, char * kekey_str)
{
    int rv;
    rv = check_device_fd();
    if(rv < 0) {
        return NFHE_DEVICE_NOTFOUND;
    }

    unsigned char kekey_bin[16];
	Str2Bn(kekey_bin, kekey_str);

    decd_ioctl_ctx data;
    data.inLen = 4 + 4 + 16;
    data.outLen = 8;
    int Command = KMG_RESTORE_KEKEY;
    int len = data.inLen < data.outLen ? data.outLen : data.inLen;
    data.pDataBuf = malloc(len + 1);

    for (int i = 0; i < card_num; i++) {
        memset(data.pDataBuf, 0, len + 1);
        memcpy(data.pDataBuf, &Command, 4);
        memcpy(data.pDataBuf + 4, &uiKeyIndex, 4);
        memcpy(data.pDataBuf + 4 + 4, kekey_bin, 16);

        rv = ioctl(device_fd[i], IOCTL_DECD, &data);
        if (rv < 0) {
            printf("IOCTL IOCTL_DECD: failed\n");
            rv = NFHE_IOCTL_ERROR;
            break;
        } else {
            memcpy(&rv, data.pDataBuf, 4);
            if (rv != 0){
                break;
            }
        }
    }

    if(data.pDataBuf) {
        free(data.pDataBuf);
    }

    if (rv != 0){
        printf("FHEKmg_Restore_KeKey: failed, rv: %x\n", rv);
        return rv;
    } else {
        printf("FHEKmg_Restore_KeKey: success\n");
    }

    return NFHE_OK;
}


int FHEKmg_Create_Sm1key(unsigned int uiKeyIndex)
{
    int rv;
    rv = check_device_fd();
    if(rv < 0) {
        return NFHE_DEVICE_NOTFOUND;
    }

    decd_ioctl_ctx data;
    data.inLen = 4 + 4;
    data.outLen = 8;
    int Command = KMG_CREATE_SM1KEY;
    int len = data.inLen < data.outLen ? data.outLen : data.inLen;
    data.pDataBuf = malloc(len + 1);

    for (int i = 0; i < card_num; i++) {
        memset(data.pDataBuf, 0, len + 1);
        memcpy(data.pDataBuf, &Command, 4);
        memcpy(data.pDataBuf + 4, &uiKeyIndex, 4);

        rv = ioctl(device_fd[i], IOCTL_DECD, &data);
        if (rv < 0) {
            printf("IOCTL IOCTL_DECD: failed\n");
            rv = NFHE_IOCTL_ERROR;
            break;
        } else {
            memcpy(&rv, data.pDataBuf, 4);
            if (rv != 0){
                break;
            }
        }
    }

    if(data.pDataBuf) {
        free(data.pDataBuf);
    }

    if (rv != 0){
        printf("FHEKmg_Create_Sm1key: failed, rv: %x\n", rv);
        return rv;
    } else {
        printf("FHEKmg_Create_Sm1key: success\n");
    }

    return NFHE_OK;
}

int FHEKmg_Backup_Sm1key(unsigned int uiKeyIndex, char * sm1key_str)
{
    int rv;
    rv = check_device_fd();
    if(rv < 0) {
        return NFHE_DEVICE_NOTFOUND;
    }
    
    decd_ioctl_ctx data;
    data.inLen = 4 + 4;
    data.outLen = 8 + 16;
    int Command = KMG_BACKUP_SM1KEY;
    int len = data.inLen < data.outLen ? data.outLen : data.inLen;
    data.pDataBuf = malloc(len + 1);
    memset(data.pDataBuf, 0, len + 1);
	memcpy(data.pDataBuf, &Command, 4);
    memcpy(data.pDataBuf + 4, &uiKeyIndex, 4);

    card_t* usedCard;
    usedCard = (card_t*)nlist_remove(&card_list);
    rv = ioctl(usedCard->fd, IOCTL_DECD, &data);
    nlist_insert(&card_list, &usedCard->node);

    if (rv < 0) {
        printf("IOCTL IOCTL_DECD: failed\n");
        rv = NFHE_IOCTL_ERROR;
    } else {
        memcpy(&rv, data.pDataBuf, 4);
    }

    if(rv == 0){
        unsigned char sm1key_bin[16];
        memcpy(sm1key_bin, data.pDataBuf + 8, 16);
        Bn2Str(sm1key_str, sm1key_bin, 16);
    }

    if(data.pDataBuf) {
        free(data.pDataBuf);
    }

    if (rv != 0){
        printf("FHEKmg_Backup_Sm1key: failed, rv: %x\n", rv);
        return rv;
    } else {
        printf("FHEKmg_Backup_Sm1key: success\n");
    }

    return NFHE_OK;
}


int FHEKmg_Restore_Sm1key(unsigned int uiKeyIndex, char * sm1key_str)
{
    int rv;
    rv = check_device_fd();
    if(rv < 0) {
        return NFHE_DEVICE_NOTFOUND;
    }

    unsigned char sm1key_bin[16];
	Str2Bn(sm1key_bin, sm1key_str);

    decd_ioctl_ctx data;
    data.inLen = 4 + 4 + 16;
    data.outLen = 8;
    int Command = KMG_RESTORE_SM1KEY;
    int len = data.inLen < data.outLen ? data.outLen : data.inLen;
    data.pDataBuf = malloc(len + 1);

    for (int i = 0; i < card_num; i++) {
        memset(data.pDataBuf, 0, len + 1);
        memcpy(data.pDataBuf, &Command, 4);
        memcpy(data.pDataBuf + 4, &uiKeyIndex, 4);
        memcpy(data.pDataBuf + 4 + 4, sm1key_bin, 16);

        rv = ioctl(device_fd[i], IOCTL_DECD, &data);
        if (rv < 0) {
            printf("IOCTL IOCTL_DECD: failed\n");
            rv = NFHE_IOCTL_ERROR;
            break;
        } else {
            memcpy(&rv, data.pDataBuf, 4);
            if (rv != 0){
                break;
            }
        }
    }

    if(data.pDataBuf) {
        free(data.pDataBuf);
    }

    if (rv != 0){
        printf("FHEKmg_Restore_Sm1key: failed, rv: %x\n", rv);
        return rv;
    } else {
        printf("FHEKmg_Restore_Sm1key: success\n");
    }

    return NFHE_OK;
}


int FHEKmg_Restore_Sm1key_PLAIN(unsigned int uiKeyIndex, char* sm1key_str) {
    int rv;
    rv = check_device_fd();
    if(rv < 0) {
        return NFHE_DEVICE_NOTFOUND;
    }

    unsigned char sm1key_bin[16];
	Str2Bn(sm1key_bin, sm1key_str);

    decd_ioctl_ctx data;
    data.inLen = 4 + 4 + 16;
    data.outLen = 8;
    int Command = KMG_RESTORE_SM1KEY_PLAIN;
    int len = data.inLen < data.outLen ? data.outLen : data.inLen;
    data.pDataBuf = malloc(len + 1);

    for (int i = 0; i < card_num; i++) {
        memset(data.pDataBuf, 0, len + 1);
        memcpy(data.pDataBuf, &Command, 4);
        memcpy(data.pDataBuf + 4, &uiKeyIndex, 4);
        memcpy(data.pDataBuf + 4 + 4, sm1key_bin, 16);

        rv = ioctl(device_fd[i], IOCTL_DECD, &data);
        if (rv < 0) {
            printf("IOCTL IOCTL_DECD: failed\n");
            rv = NFHE_IOCTL_ERROR;
            break;
        } else {
            memcpy(&rv, data.pDataBuf, 4);
            if (rv != 0){
                break;
            }
        }
    }

    if(data.pDataBuf) {
        free(data.pDataBuf);
    }

    if (rv != 0){
        printf("FHEKmg_Restore_Sm1key_PLAIN: failed, rv: %x\n", rv);
        return rv;
    } else {
        printf("FHEKmg_Restore_Sm1key_PLAIN: success\n");
    }

    return NFHE_OK;
}


int FHEKmg_Create_FheAuth(unsigned int uiIndex)
{
    int rv;
    rv = check_device_fd();
    if(rv < 0) {
        return NFHE_DEVICE_NOTFOUND;
    }

    decd_ioctl_ctx data;
    data.inLen = 4 + 4;
    data.outLen = 8;
    int Command = KMG_CREATE_SM1AUTH;
    int len = data.inLen < data.outLen ? data.outLen : data.inLen;
    data.pDataBuf = malloc(len + 1);

    for (int i = 0; i < card_num; i++) {
        memset(data.pDataBuf, 0, len + 1);
        memcpy(data.pDataBuf, &Command, 4);
        memcpy(data.pDataBuf + 4, &uiIndex, 4);

        rv = ioctl(device_fd[i], IOCTL_DECD, &data);
        if (rv < 0) {
            printf("IOCTL IOCTL_DECD: failed\n");
            rv = NFHE_IOCTL_ERROR;
            break;
        } else {
            memcpy(&rv, data.pDataBuf, 4);
            if (rv != 0){
                break;
            }
        }
    }

    if(data.pDataBuf) {
        free(data.pDataBuf);
    }

    if (rv != 0){
        printf("FHEKmg_Create_FheAuth: failed, rv: %x\n", rv);
        return rv;
    } else {
        printf("FHEKmg_Create_FheAuth: success\n");
    }

    return NFHE_OK;
}


int FHEKmg_Backup_FheAuth(unsigned int uiIndex, char* sm1key_auth_str)
{
    int rv;
    rv = check_device_fd();
    if(rv < 0) {
        return NFHE_DEVICE_NOTFOUND;
    }

    decd_ioctl_ctx data;
    data.inLen = 4 + 4;
    data.outLen = 8 + 16;
    int Command = KMG_BACKUP_SM1AUTH;
    int len = data.inLen < data.outLen ? data.outLen : data.inLen;
    data.pDataBuf = malloc(len + 1);
    memset(data.pDataBuf, 0, len + 1);
	memcpy(data.pDataBuf, &Command, 4);
    memcpy(data.pDataBuf + 4, &uiIndex, 4);

    card_t* usedCard;
    usedCard = (card_t*)nlist_remove(&card_list);
    rv = ioctl(usedCard->fd, IOCTL_DECD, &data);
    nlist_insert(&card_list, &usedCard->node);

    if (rv < 0) {
        printf("IOCTL IOCTL_DECD: failed\n");
        rv = NFHE_IOCTL_ERROR;
    } else {
        memcpy(&rv, data.pDataBuf, 4);
    }

    if(rv == 0){
        unsigned char sm1key_auth_bin[16];
        memcpy(sm1key_auth_bin, data.pDataBuf + 8, 16);
        Bn2Str(sm1key_auth_str, sm1key_auth_bin, 16);
    }

    if(data.pDataBuf) {
        free(data.pDataBuf);
    }

    if (rv != 0){
        printf("FHEKmg_Backup_FheAuth: failed, rv: %x\n", rv);
        return rv;
    } else {
        printf("FHEKmg_Backup_FheAuth: success\n");
    }

    return NFHE_OK;
}


int FHEKmg_Restore_FheAuth(unsigned int uiIndex, char* sm1key_auth_str)
{
    int rv;
    rv = check_device_fd();
    if(rv < 0) {
        return NFHE_DEVICE_NOTFOUND;
    }

    unsigned char sm1key_auth_bin[16];
	Str2Bn(sm1key_auth_bin, sm1key_auth_str);

    decd_ioctl_ctx data;
    data.inLen = 4 + 4 + 16;
    data.outLen = 8;
    int Command = KMG_RESTORE_SM1AUTH;
    int len = data.inLen < data.outLen ? data.outLen : data.inLen;
    data.pDataBuf = malloc(len + 1);

    for (int i = 0; i < card_num; i++) {
        memset(data.pDataBuf, 0, len + 1);
        memcpy(data.pDataBuf, &Command, 4);
        memcpy(data.pDataBuf + 4, &uiIndex, 4);
        memcpy(data.pDataBuf + 4 + 4, sm1key_auth_bin, 16);

        rv = ioctl(device_fd[i], IOCTL_DECD, &data);
        if (rv < 0) {
            printf("IOCTL IOCTL_DECD: failed\n");
            rv = NFHE_IOCTL_ERROR;
            break;
        } else {
            memcpy(&rv, data.pDataBuf, 4);
            if (rv != 0){
                break;
            }
        }
    }

    if(data.pDataBuf) {
        free(data.pDataBuf);
    }

    if (rv != 0){
        printf("FHEKmg_Restore_FheAuth: failed, rv: %x\n", rv);
        return rv;
    } else {
        printf("FHEKmg_Restore_FheAuth: success\n");
    }

    return NFHE_OK;
}


int FHEKMG_GenerateExportFheKeypair(unsigned int uiKeyIndex, char* fhepubkey_str)
{
#if IS_MULTI_CARD(card_num)

    return NFHE_NOT_DEFINED;

#else
    int rv;
    rv = check_device_fd();
    if(rv < 0) {
        return NFHE_DEVICE_NOTFOUND;
    }

	// NFHE_GenerateFheKeypair
    card_t* usedCard;
    usedCard = (card_t*)nlist_remove(&card_list);
    rv = ioctl(usedCard->fd, IOCTL_FHE_GENKEY, NULL);
    nlist_insert(&card_list, &usedCard->node);

    if (rv < 0) {
        printf("IOCTL IOCTL_FHE_GENKEY: failed\n");
        return NFHE_IOCTL_ERROR;
    }
    
    // NFHE_ExportFhePubKey
    unsigned char fhepubkey_bin[FHE_PUBKEY_BYTES];

    usedCard = (card_t*)nlist_remove(&card_list);
    rv = ioctl(usedCard->fd, IOCTL_NFHE_EXPORT_PUBKEY, fhepubkey_bin);
    nlist_insert(&card_list, &usedCard->node);

    if (rv < 0) {
        printf("IOCTL IOCTL_DECD: failed\n");
        rv = NFHE_IOCTL_ERROR;
    } else {
        Bn2Str(fhepubkey_str, fhepubkey_bin, FHE_PUBKEY_BYTES);
    }
    
    // FHEKmg_SaveFhePriKey
    decd_ioctl_ctx data;
    data.inLen = 4 + 4;
    data.outLen = 8;
    int Command = KMG_NFHE_SAVEFHEPRIKEY;
    int len = data.inLen < data.outLen ? data.outLen : data.inLen;
    data.pDataBuf = malloc(len + 1);
    memset(data.pDataBuf, 0, len + 1);
	memcpy(data.pDataBuf, &Command, 4);
    memcpy(data.pDataBuf + 4, &uiKeyIndex, 4);

    usedCard = (card_t*)nlist_remove(&card_list);
    rv = ioctl(usedCard->fd, IOCTL_DECD, &data);
    nlist_insert(&card_list, &usedCard->node);

    if (rv < 0) {
        printf("IOCTL IOCTL_DECD: failed\n");
        rv = NFHE_IOCTL_ERROR;
    } else {
        memcpy(&rv, data.pDataBuf, 4);
    }

    if(data.pDataBuf) {
        free(data.pDataBuf);
    }
    if (rv != 0){
        printf("FHEKMG_GenerateExportFheKeypair: failed, rv: %x\n", rv);
        return rv;
    } else {
        printf("FHEKMG_GenerateExportFheKeypair: success\n");
    }

    return NFHE_OK; 

#endif
}


int FHEKmg_ImportLoadFhePubKey(char* fhepubkey_str)
{
#if IS_MULTI_CARD(card_num)

    return NFHE_NOT_DEFINED;

#else

    int rv;
    rv = check_device_fd();
    if(rv < 0) {
        return NFHE_DEVICE_NOTFOUND;
    }

    unsigned char fhepubkey_bin[FHE_PUBKEY_BYTES];
    Str2Bn(fhepubkey_bin, fhepubkey_str);

    card_t* usedCard;
    usedCard = (card_t*)nlist_remove(&card_list);
    rv = ioctl(usedCard->fd, IOCTL_NFHE_IMPORT_PUBKEY, fhepubkey_bin);
    nlist_insert(&card_list, &usedCard->node);

    if (rv < 0) {
        printf("IOCTL IOCTL_DECD: failed\n");
        rv = NFHE_IOCTL_ERROR;
    }

	//Set GlbFheSM1Key in MCS
    decd_ioctl_ctx data;
    data.inLen = 4 + 4;
    data.outLen = 8;
    int Command = KMG_LOADFHEPUBKEY;
    int len = data.inLen < data.outLen ? data.outLen : data.inLen;
    data.pDataBuf = malloc(len + 1);
    memset(data.pDataBuf, 0, len + 1);
	memcpy(data.pDataBuf, &Command, 4);

    usedCard = (card_t*)nlist_remove(&card_list);
    rv = ioctl(usedCard->fd, IOCTL_DECD, &data);
    nlist_insert(&card_list, &usedCard->node);

    if (rv < 0) {
        printf("IOCTL IOCTL_DECD: failed\n");
        rv = NFHE_IOCTL_ERROR;
    } else {
        memcpy(&rv, data.pDataBuf, 4);
    }

    if(data.pDataBuf) {
        free(data.pDataBuf);
    }
    if (rv != 0){
        printf("FHEKmg_ImportLoadFhePubKey: failed, rv: %x\n", rv);
        return rv;
    } else {
        printf("FHEKmg_ImportLoadFhePubKey: success\n");
    }
	
    return NFHE_OK;


#endif
}


/**
 * @brief 将 fpga 中的 fheprikey 保存到 flash
 * 
 * @param uiKeyIndex 
 * @return int 
 */
int FHEKmg_SaveFhePriKey(unsigned int uiKeyIndex)
{
#if IS_MULTI_CARD(card_num)

    return NFHE_NOT_DEFINED;

#else
    int rv;
    rv = check_device_fd();
    if(rv < 0) {
        return NFHE_DEVICE_NOTFOUND;
    }

    decd_ioctl_ctx data;
    data.inLen = 4 + 4;
    data.outLen = 8;
    int Command = KMG_NFHE_SAVEFHEPRIKEY;
    int len = data.inLen < data.outLen ? data.outLen : data.inLen;
    data.pDataBuf = malloc(len + 1);
    memset(data.pDataBuf, 0, len + 1);
	memcpy(data.pDataBuf, &Command, 4);
    memcpy(data.pDataBuf + 4, &uiKeyIndex, 4);

    card_t* usedCard;
    usedCard = (card_t*)nlist_remove(&card_list);
    rv = ioctl(usedCard->fd, IOCTL_DECD, &data);
    nlist_insert(&card_list, &usedCard->node);

    if (rv < 0) {
        printf("IOCTL IOCTL_DECD: failed\n");
        rv = NFHE_IOCTL_ERROR;
    } else {
        memcpy(&rv, data.pDataBuf, 4);
    }

    if(data.pDataBuf) {
        free(data.pDataBuf);
    }
    if (rv != 0){
        printf("FHEKmg_SaveFhePriKey: failed, rv: %x\n", rv);
        return rv;
    } else {
        printf("FHEKmg_SaveFhePriKey: success\n");
    }

    return NFHE_OK;
#endif
}

/**
 * @brief 将 flash 中的 fheprikey 加载到 fpga
 * 
 * @param uiKeyIndex 
 * @return int 
 */
int FHEKmg_LoadFhePriKey(unsigned int uiKeyIndex)
{
#if IS_MULTI_CARD(card_num)

    return NFHE_NOT_DEFINED;

#else
    int rv;
    rv = check_device_fd();
    if(rv < 0) {
        return NFHE_DEVICE_NOTFOUND;
    }

    decd_ioctl_ctx data;
    data.inLen = 4 + 4;
    data.outLen = 8;
    int Command = KMG_NFHE_LOADFHEPRIKEY;
    int len = data.inLen < data.outLen ? data.outLen : data.inLen;
    data.pDataBuf = malloc(len + 1);
    memset(data.pDataBuf, 0, len + 1);
	memcpy(data.pDataBuf, &Command, 4);
    memcpy(data.pDataBuf + 4, &uiKeyIndex, 4);

    card_t* usedCard;
    usedCard = (card_t*)nlist_remove(&card_list);
    rv = ioctl(usedCard->fd, IOCTL_DECD, &data);
    nlist_insert(&card_list, &usedCard->node);

    if (rv < 0) {
        printf("IOCTL IOCTL_DECD: failed\n");
        rv = NFHE_IOCTL_ERROR;
    } else {
        memcpy(&rv, data.pDataBuf, 4);
    }

    if(data.pDataBuf) {
        free(data.pDataBuf);
    }
    if (rv != 0){
        printf("FHEKmg_LoadFhePriKey: failed, rv: %x\n", rv);
        return rv;
    } else {
        printf("FHEKmg_LoadFhePriKey: success\n");
    }

    return NFHE_OK;
#endif
}

/**
 * @brief 将 flash 中的 fheprikey 导出到 上位机
 * 
 * @param uiKeyIndex 
 * @param pucBpKey 
 * @return int 
 */
int FHEKmg_BackupFHEPriKey(unsigned int uiKeyIndex, char* fheprikey_str)
{
#if IS_MULTI_CARD(card_num)

    return NFHE_NOT_DEFINED;

#else
    int rv;
    rv = check_device_fd();
    if(rv < 0) {
        return NFHE_DEVICE_NOTFOUND;
    }

    decd_ioctl_ctx data;
    data.inLen = 4 + 4;
    data.outLen = 8 + FHE_PRIKEY_BYTES;
    int Command = KMG_NFHE_BACKUPFHEPRIKEY;
    
    int len = data.inLen < data.outLen ? data.outLen : data.inLen;
    data.pDataBuf = malloc(len + 1);
    memset(data.pDataBuf, 0, len + 1);
	memcpy(data.pDataBuf, &Command, 4);
    memcpy(data.pDataBuf + 4, &uiKeyIndex, 4);

    card_t* usedCard;
    usedCard = (card_t*)nlist_remove(&card_list);
    rv = ioctl(usedCard->fd, IOCTL_DECD, &data);
    nlist_insert(&card_list, &usedCard->node);

    if (rv < 0) {
        printf("IOCTL IOCTL_DECD: failed\n");
        rv = NFHE_IOCTL_ERROR;
    } else {
        memcpy(&rv, data.pDataBuf, 4);
    }
    if(rv == 0){
        unsigned char fheprikey_bin[FHE_PRIKEY_BYTES];
        memcpy(fheprikey_bin, data.pDataBuf + 8, FHE_PRIKEY_BYTES);
		Bn2Str(fheprikey_str, fheprikey_bin, FHE_PRIKEY_BYTES);
    }

    if(data.pDataBuf) {
        free(data.pDataBuf);
    }
    if (rv != 0){
        printf("FHEKmg_BackupFHEPriKey: failed, rv: %x\n", rv);
        return rv;
    } else {
        printf("FHEKmg_BackupFHEPriKey: success\n");
    }

    return NFHE_OK;
#endif
}

/**
 * @brief 将 上位机 传入的 fheprikey 写入 flash
 * 
 * @param uiKeyIndex 
 * @param pucBpKey 
 * @return int 
 */
int FHEKmg_RestoreFHEPriKey(unsigned int uiKeyIndex, char* fheprikey_str)
{
#if IS_MULTI_CARD(card_num)

    return NFHE_NOT_DEFINED;

#else
    int rv;
    rv = check_device_fd();
    if(rv < 0) {
        return NFHE_DEVICE_NOTFOUND;
    }
    unsigned char fheprikey_bin[FHE_PRIKEY_BYTES];
    Str2Bn(fheprikey_bin, fheprikey_str);

    decd_ioctl_ctx data;
    data.inLen = 4 + 4 + FHE_PRIKEY_BYTES;
    data.outLen = 8;
    int Command = KMG_NFHE_RESTOREFHEPRIKEY;
    int len = data.inLen < data.outLen ? data.outLen : data.inLen;
    data.pDataBuf = malloc(len + 1);
    memset(data.pDataBuf, 0, len + 1);
	memcpy(data.pDataBuf, &Command, 4);
    memcpy(data.pDataBuf + 4, &uiKeyIndex, 4);
    memcpy(data.pDataBuf + 4 + 4, fheprikey_bin, FHE_PRIKEY_BYTES);

    card_t* usedCard;
    usedCard = (card_t*)nlist_remove(&card_list);
    rv = ioctl(usedCard->fd, IOCTL_DECD, &data);
    nlist_insert(&card_list, &usedCard->node);

    if (rv < 0) {
        printf("IOCTL IOCTL_DECD: failed\n");
        rv = NFHE_IOCTL_ERROR;
    } else {
        memcpy(&rv, data.pDataBuf, 4);
    }

    if(data.pDataBuf) {
        free(data.pDataBuf);
    }
    if (rv != 0){
        printf("FHEKmg_RestoreFHEPriKey: failed, rv: %x\n", rv);
        return rv;
    } else {
        printf("FHEKmg_RestoreFHEPriKey: success\n");
    }

    return NFHE_OK;
#endif
}


int FHEKmg_Create_And_Backup_FheKeyPair(unsigned int uiIndex, char* pucPublicKey, char* pucPrivateKey) {
    int rv;
    rv = check_device_fd();
    if(rv < 0) {
        return NFHE_DEVICE_NOTFOUND;
    }

    for (int i = 0; i < card_num; i++) {
        // NFHE_GenerateFheKeypair
        rv = ioctl(device_fd[i], IOCTL_FHE_GENKEY, NULL);
        if (rv < 0) {
            printf("IOCTL IOCTL_FHE_GENKEY: failed\n");
            rv = NFHE_IOCTL_ERROR;
            return rv;
        }
    }

    // NFHE_ExportFhePubKey
    unsigned char *fhepubkey_bin = (unsigned char *)malloc(sizeof(unsigned char) * FHE_PUBKEY_BYTES);
    rv = ioctl(device_fd[0], IOCTL_NFHE_EXPORT_PUBKEY, fhepubkey_bin);
    if (rv < 0) {
        printf("IOCTL IOCTL_DECD: failed\n");
        rv = NFHE_IOCTL_ERROR;
        return rv;
    } else {
        Bn2Str(pucPublicKey, fhepubkey_bin, FHE_PUBKEY_BYTES);
    }

    // FHEKmg_SaveFhePriKey
    decd_ioctl_ctx data;
    data.inLen = 4 + 4;
    data.outLen = 8;
    int Command = KMG_NFHE_SAVEFHEPRIKEY;
    int len = data.inLen < data.outLen ? data.outLen : data.inLen;
    data.pDataBuf = malloc(len + 1);
    memset(data.pDataBuf, 0, len + 1);
    memcpy(data.pDataBuf, &Command, 4);
    memcpy(data.pDataBuf + 4, &uiIndex, 4);

    rv = ioctl(device_fd[0], IOCTL_DECD, &data);
    if (rv < 0) {
        printf("IOCTL IOCTL_DECD: failed\n");
        rv = NFHE_IOCTL_ERROR;
    } else {
        memcpy(&rv, data.pDataBuf, 4);
    }

    if(data.pDataBuf) {
        free(data.pDataBuf);
    }
    if (rv != 0){
        printf("KMG_NFHE_SAVEFHEPRIKEY: failed, rv: %x\n", rv);
        return rv;
    } else {
        printf("KMG_NFHE_SAVEFHEPRIKEY: success\n");
    }

    data.inLen = 4 + 4;
    data.outLen = 8 + FHE_PRIKEY_BYTES;
    Command = KMG_NFHE_BACKUPFHEPRIKEY;
    len = data.inLen < data.outLen ? data.outLen : data.inLen;
    data.pDataBuf = malloc(len + 1);
    memset(data.pDataBuf, 0, len + 1);
    memcpy(data.pDataBuf, &Command, 4);
    memcpy(data.pDataBuf + 4, &uiIndex, 4);

    rv = ioctl(device_fd[0], IOCTL_DECD, &data);
    if (rv < 0) {
        printf("IOCTL IOCTL_DECD: failed\n");
        rv = NFHE_IOCTL_ERROR;
    } else {
        memcpy(&rv, data.pDataBuf, 4);
    }

    if(rv == 0){
        unsigned char *fheprikey_bin = (unsigned char *)malloc(sizeof(unsigned char) * FHE_PRIKEY_BYTES);
        memcpy(fheprikey_bin, data.pDataBuf + 8, FHE_PRIKEY_BYTES);
        Bn2Str(pucPrivateKey, fheprikey_bin, FHE_PRIKEY_BYTES);
        if (fheprikey_bin)
		    free(fheprikey_bin);
    }

    if(data.pDataBuf) {
        free(data.pDataBuf);
    }

    if (rv != 0){
        printf("KMG_NFHE_BACKUPFHEPRIKEY: failed, rv: %x\n", rv);
        return rv;
    } else {
        printf("KMG_NFHE_BACKUPFHEPRIKEY: success\n");
    }

    if (fhepubkey_bin)
		free(fhepubkey_bin);

    return FHEKmg_Restore_FheKeyPair(uiIndex, pucPublicKey, pucPrivateKey);
}


int FHEKmg_Restore_FheKeyPair(unsigned int uiIndex, char* pucPublicKey, char* pucPrivateKey) {
    int rv;
    rv = check_device_fd();
    if(rv < 0) {
        return NFHE_DEVICE_NOTFOUND;
    }

    unsigned char *fhepubkey_bin = (unsigned char *)malloc(sizeof(unsigned char) * FHE_PUBKEY_BYTES);
    unsigned char *fheprikey_bin = (unsigned char *)malloc(sizeof(unsigned char) * FHE_PRIKEY_BYTES);
    Str2Bn(fhepubkey_bin, pucPublicKey);
    Str2Bn(fheprikey_bin, pucPrivateKey);

    for (int i = 0; i < card_num; i++) {
        rv = ioctl(device_fd[i], IOCTL_NFHE_IMPORT_PUBKEY, fhepubkey_bin);
        if (rv < 0) {
            printf("IOCTL IOCTL_DECD: failed\n");
            rv = NFHE_IOCTL_ERROR;
            return rv;
        }

        //Set GlbFheSM1Key in MCS
        decd_ioctl_ctx data;
        data.inLen = 4 + 4;
        data.outLen = 8;
        int Command = KMG_LOADFHEPUBKEY;
        int len = data.inLen < data.outLen ? data.outLen : data.inLen;
        data.pDataBuf = malloc(len + 1);
        memset(data.pDataBuf, 0, len + 1);
        memcpy(data.pDataBuf, &Command, 4);

        rv = ioctl(device_fd[i], IOCTL_DECD, &data);
        if (rv < 0) {
            printf("IOCTL IOCTL_DECD: failed\n");
            rv = NFHE_IOCTL_ERROR;
            return rv;
        } else {
            memcpy(&rv, data.pDataBuf, 4);
        }

        if(data.pDataBuf) {
            free(data.pDataBuf);
        }

        if (rv != 0){
            printf("FHEKmg_ImportLoadFhePubKey: failed, rv: %x\n", rv);
            return rv;
        } else {
            printf("FHEKmg_ImportLoadFhePubKey: success\n");
        }

        data.inLen = 4 + 4 + FHE_PRIKEY_BYTES;
        data.outLen = 8;
        Command = KMG_NFHE_RESTOREFHEPRIKEY;
        len = data.inLen < data.outLen ? data.outLen : data.inLen;
        data.pDataBuf = malloc(len + 1);
        memset(data.pDataBuf, 0, data.inLen + 1);
        memcpy(data.pDataBuf, &Command, 4);
        memcpy(data.pDataBuf + 4, &uiIndex, 4);
        memcpy(data.pDataBuf + 4 + 4, fheprikey_bin, FHE_PRIKEY_BYTES);

        rv = ioctl(device_fd[i], IOCTL_DECD, &data);
        if (rv < 0) {
            printf("IOCTL IOCTL_DECD: failed\n");
            rv = NFHE_IOCTL_ERROR;
            return rv;
        } else {
            memcpy(&rv, data.pDataBuf, 4);
        }

        if(data.pDataBuf) {
            free(data.pDataBuf);
        }

        if (rv != 0){
            printf("FHEKmg_RestoreFHEPriKey: failed, rv: %x\n", rv);
            return rv;
        } else {
            printf("FHEKmg_RestoreFHEPriKey: success\n");
        }

        unsigned int uiKeyIndex = 1;
        data.inLen = 4 + 4;
        data.outLen = 8;
        Command = KMG_NFHE_LOADFHEPRIKEY;
        len = data.inLen < data.outLen ? data.outLen : data.inLen;
        data.pDataBuf = malloc(len + 1);
        memset(data.pDataBuf, 0, len + 1);
        memcpy(data.pDataBuf, &Command, 4);
        memcpy(data.pDataBuf + 4, &uiKeyIndex, 4);

        rv = ioctl(device_fd[i], IOCTL_DECD, &data);
        if (rv < 0) {
            printf("IOCTL IOCTL_DECD: failed\n");
            rv = NFHE_IOCTL_ERROR;
            return rv;
        } else {
            memcpy(&rv, data.pDataBuf, 4);
        }

        if(data.pDataBuf) {
            free(data.pDataBuf);
        }
        if (rv != 0){
            printf("FHEKmg_LoadFhePriKey: failed, rv: %x\n", rv);
            return rv;
        } else {
            printf("FHEKmg_LoadFhePriKey: success\n");
        }
    }

    if (fhepubkey_bin)
		free(fhepubkey_bin);
    if (fheprikey_bin)
        free(fheprikey_bin);

    return NFHE_OK;
}

int FHEKmg_Backup_FhePriKey(unsigned int uiIndex, char* pucPrivateKey) {
    int rv;
    rv = check_device_fd();
    if(rv < 0) {
        return NFHE_DEVICE_NOTFOUND;
    }

    // FHEKmg_SaveFhePriKey
    decd_ioctl_ctx data;
    data.inLen = 4 + 4;
    data.outLen = 8;
    int Command = KMG_NFHE_SAVEFHEPRIKEY;
    int len = data.inLen < data.outLen ? data.outLen : data.inLen;
    data.pDataBuf = malloc(len + 1);
    memset(data.pDataBuf, 0, len + 1);
    memcpy(data.pDataBuf, &Command, 4);
    memcpy(data.pDataBuf + 4, &uiIndex, 4);

    rv = ioctl(device_fd[0], IOCTL_DECD, &data);
    if (rv < 0) {
        printf("IOCTL IOCTL_DECD: failed\n");
        rv = NFHE_IOCTL_ERROR;
    } else {
        memcpy(&rv, data.pDataBuf, 4);
    }

    if(data.pDataBuf) {
        free(data.pDataBuf);
    }
    if (rv != 0){
        printf("KMG_NFHE_SAVEFHEPRIKEY: failed, rv: %x\n", rv);
        return rv;
    } else {
        printf("KMG_NFHE_SAVEFHEPRIKEY: success\n");
    }

    data.inLen = 4 + 4;
    data.outLen = 8 + FHE_PRIKEY_BYTES;
    Command = KMG_NFHE_BACKUPFHEPRIKEY;
    len = data.inLen < data.outLen ? data.outLen : data.inLen;
    data.pDataBuf = malloc(len + 1);
    memset(data.pDataBuf, 0, len + 1);
    memcpy(data.pDataBuf, &Command, 4);
    memcpy(data.pDataBuf + 4, &uiIndex, 4);

    rv = ioctl(device_fd[0], IOCTL_DECD, &data);
    if (rv < 0) {
        printf("IOCTL IOCTL_DECD: failed\n");
        rv = NFHE_IOCTL_ERROR;
    } else {
        memcpy(&rv, data.pDataBuf, 4);
    }

    if(rv == 0){
        unsigned char *fheprikey_bin = (unsigned char *)malloc(sizeof(unsigned char) * FHE_PRIKEY_BYTES);
        memcpy(fheprikey_bin, data.pDataBuf + 8, FHE_PRIKEY_BYTES);
        Bn2Str(pucPrivateKey, fheprikey_bin, FHE_PRIKEY_BYTES);
        if (fheprikey_bin)
		    free(fheprikey_bin);
    }

    if(data.pDataBuf) {
        free(data.pDataBuf);
    }

    if (rv != 0){
        printf("KMG_NFHE_BACKUPFHEPRIKEY: failed, rv: %x\n", rv);
        return rv;
    } else {
        printf("KMG_NFHE_BACKUPFHEPRIKEY: success\n");
    }

    

    return rv;
}

int FHEKmg_Restore_FhePriKey(unsigned int uiIndex, char* pucPrivateKey) {
    int rv;
    rv = check_device_fd();
    if(rv < 0) {
        return NFHE_DEVICE_NOTFOUND;
    }

    unsigned char *fheprikey_bin = (unsigned char *)malloc(sizeof(unsigned char) * FHE_PRIKEY_BYTES);
    Str2Bn(fheprikey_bin, pucPrivateKey);

    for (int i = 0; i < card_num; i++) {
        decd_ioctl_ctx data;
        data.inLen = 4 + 4 + FHE_PRIKEY_BYTES;
        data.outLen = 8;
        int Command = KMG_NFHE_RESTOREFHEPRIKEY;
        int len = data.inLen < data.outLen ? data.outLen : data.inLen;
        data.pDataBuf = malloc(len + 1);
        memset(data.pDataBuf, 0, data.inLen + 1);
        memcpy(data.pDataBuf, &Command, 4);
        memcpy(data.pDataBuf + 4, &uiIndex, 4);
        memcpy(data.pDataBuf + 4 + 4, fheprikey_bin, FHE_PRIKEY_BYTES);

        rv = ioctl(device_fd[i], IOCTL_DECD, &data);
        if (rv < 0) {
            printf("IOCTL IOCTL_DECD: failed\n");
            rv = NFHE_IOCTL_ERROR;
            return rv;
        } else {
            memcpy(&rv, data.pDataBuf, 4);
        }

        if(data.pDataBuf) {
            free(data.pDataBuf);
        }

        if (rv != 0){
            printf("FHEKmg_RestoreFHEPriKey: failed, rv: %x\n", rv);
            return rv;
        } else {
            printf("FHEKmg_RestoreFHEPriKey: success\n");
        }

        unsigned int uiKeyIndex = 1;
        data.inLen = 4 + 4;
        data.outLen = 8;
        Command = KMG_NFHE_LOADFHEPRIKEY;
        len = data.inLen < data.outLen ? data.outLen : data.inLen;
        data.pDataBuf = malloc(len + 1);
        memset(data.pDataBuf, 0, len + 1);
        memcpy(data.pDataBuf, &Command, 4);
        memcpy(data.pDataBuf + 4, &uiKeyIndex, 4);

        rv = ioctl(device_fd[i], IOCTL_DECD, &data);
        if (rv < 0) {
            printf("IOCTL IOCTL_DECD: failed\n");
            rv = NFHE_IOCTL_ERROR;
            return rv;
        } else {
            memcpy(&rv, data.pDataBuf, 4);
        }

        if(data.pDataBuf) {
            free(data.pDataBuf);
        }
        if (rv != 0){
            printf("FHEKmg_LoadFhePriKey: failed, rv: %x\n", rv);
            return rv;
        } else {
            printf("FHEKmg_LoadFhePriKey: success\n");
        }
    }

    if (fheprikey_bin)
		free(fheprikey_bin);

    return NFHE_OK;
}

int FHEKmg_Create_UsrKeyPair(unsigned int uiKeyIndex, unsigned char* pucUkAccessCode, unsigned int uiUkAccessCodeLength)
{
    int rv;
    rv = check_device_fd();
    if(rv < 0) {
        return NFHE_DEVICE_NOTFOUND;
    }

    if(uiKeyIndex == 0){
        return NFHE_KEYINDEX_INVALID;
    }

    decd_ioctl_ctx data;
    data.inLen = 4 + 4 + 4 + uiUkAccessCodeLength;
    data.outLen = 8;
    int Command = KMG_CREATE_USRKEYPAIR;
    int len = data.inLen < data.outLen ? data.outLen : data.inLen;
    data.pDataBuf = malloc(len + 1);
    memset(data.pDataBuf, 0, len + 1);

    for (int i = 0; i < card_num; i++) {
        memcpy(data.pDataBuf, &Command, 4);
        memcpy(data.pDataBuf + 4, &uiKeyIndex, 4);
        memcpy(data.pDataBuf + 4 + 4, &uiUkAccessCodeLength, 4);
        memcpy(data.pDataBuf + 4 + 4 + 4, pucUkAccessCode, uiUkAccessCodeLength);

        card_t* usedCard;
        usedCard = (card_t*)nlist_remove(&card_list);
        rv = ioctl(usedCard->fd, IOCTL_DECD, &data);
        nlist_insert(&card_list, &usedCard->node);

        if (rv < 0) {
            printf("IOCTL IOCTL_DECD: failed\n");
            rv = NFHE_IOCTL_ERROR;
            break;
        } else {
            memcpy(&rv, data.pDataBuf, 4);
            if (rv != 0){
                break;
            }
        }
    }
	
    if(data.pDataBuf) {
        free(data.pDataBuf);
    }

    if (rv != 0){
        printf("FHEKmg_Create_UsrKeyPair: failed, rv: %x\n", rv);
        return rv;
    } else {
        printf("FHEKmg_Create_UsrKeyPair: success\n");
    }

    return NFHE_OK;
}


int FHEKmg_Backup_UsrKeyPair(unsigned int uiKeyIndex, char* usrkeypair_str)
{
    int rv;
    rv = check_device_fd();
    if(rv < 0) {
        return NFHE_DEVICE_NOTFOUND;
    }

    if(uiKeyIndex == 0){
        return NFHE_KEYINDEX_INVALID;
    }
    
    decd_ioctl_ctx data;
    data.inLen = 4 + 4;
    data.outLen = 8 + 192;
    int Command = KMG_BACKUP_USRKEYPAIR;
    int len = data.inLen < data.outLen ? data.outLen : data.inLen;
    data.pDataBuf = malloc(len + 1);
    memset(data.pDataBuf, 0, len + 1);
	memcpy(data.pDataBuf, &Command, 4);
    memcpy(data.pDataBuf + 4, &uiKeyIndex, 4);

    card_t* usedCard;
    usedCard = (card_t*)nlist_remove(&card_list);
    rv = ioctl(usedCard->fd, IOCTL_DECD, &data);
    nlist_insert(&card_list, &usedCard->node);
    
    if (rv < 0) {
        printf("IOCTL IOCTL_DECD: failed\n");
        rv = NFHE_IOCTL_ERROR;
    } else {
        memcpy(&rv, data.pDataBuf, 4); 
    }
    if(rv == 0){
        unsigned char usrkeypair_bin[192];
        memcpy(usrkeypair_bin, data.pDataBuf + 8, 192);
        Bn2Str(usrkeypair_str, usrkeypair_bin, 192);
    }

    if(data.pDataBuf) {
        free(data.pDataBuf);
    }

    if (rv != 0){
        printf("FHEKmg_Backup_UsrKeyPair: failed, rv: %x\n", rv);
        return rv;
    } else {
        printf("FHEKmg_Backup_UsrKeyPair: success\n");
    }

    return NFHE_OK;
}


int FHEKmg_Restore_UsrKeyPair(unsigned int uiKeyIndex, char* usrkeypair_str)
{
    int rv;
    rv = check_device_fd();
    if(rv < 0) {
        return NFHE_DEVICE_NOTFOUND;
    }

    if(uiKeyIndex == 0){
        return NFHE_KEYINDEX_INVALID;
    }

    unsigned char usrkeypair_bin[192];
	Str2Bn(usrkeypair_bin, usrkeypair_str);

    decd_ioctl_ctx data;
    data.inLen = 4 + 4 + 192;
    data.outLen = 8;
    int Command = KMG_RESTORE_USRKEYPAIR;
    int len = data.inLen < data.outLen ? data.outLen : data.inLen;
    data.pDataBuf = malloc(len + 1);

    for (int i = 0; i < card_num; i++) {
        memset(data.pDataBuf, 0, len + 1);
        memcpy(data.pDataBuf, &Command, 4);
        memcpy(data.pDataBuf + 4, &uiKeyIndex, 4);
        memcpy(data.pDataBuf + 4 + 4, usrkeypair_bin, 192);

        rv = ioctl(device_fd[i], IOCTL_DECD, &data);
        if (rv < 0) {
            printf("IOCTL IOCTL_DECD: failed\n");
            rv = NFHE_IOCTL_ERROR;
            break;
        } else {
            memcpy(&rv, data.pDataBuf, 4);
            if (rv != 0){
                break;
            }
        }
    }

    if(data.pDataBuf) {
        free(data.pDataBuf);
    }

    if (rv != 0){
        printf("FHEKmg_Restore_UsrKeyPair: failed, rv: %x\n", rv);
        return rv;
    } else {
        printf("FHEKmg_Restore_UsrKeyPair: success\n");
    }

    return NFHE_OK;
}


int FHE_SM2Key(char* pucPublicKey, char* pucPrivateKey) {
#if IS_MULTI_CARD(card_num)
    return NFHE_NOT_DEFINED;
#else

    ECCrefPublicKey PublicKey;
	ECCrefPrivateKey PrivateKey;

    int rv;
    rv = check_device_fd();
    if(rv < 0) {
        return NFHE_DEVICE_NOTFOUND;
    }

    unsigned int uiAlgID = SGD_SM2_1;
    unsigned int uiKeyBits = ECCref_MAX_BITS;
    decd_ioctl_ctx data;
    data.inLen = 4 + 4 + 4;
    data.outLen = 8 + sizeof(ECCrefPublicKey) + sizeof(ECCrefPrivateKey);
    int Command = SDF_GENERATEKEYPAIR_ECC;
    int len = data.inLen < data.outLen ? data.outLen : data.inLen;
    data.pDataBuf = malloc(len + 1);
    memset(data.pDataBuf, 0, len + 1);
	memcpy(data.pDataBuf, &Command, 4);
    memcpy(data.pDataBuf + 4, &uiAlgID, 4);
    memcpy(data.pDataBuf + 4 + 4, &uiKeyBits, 4);

    card_t* usedCard;
    usedCard = (card_t*)nlist_remove(&card_list);
    rv = ioctl(usedCard->fd, IOCTL_DECD, &data);
    nlist_insert(&card_list, &usedCard->node);

    if (rv < 0) {
        printf("IOCTL IOCTL_DECD: failed\n");
        rv = NFHE_IOCTL_ERROR;
    } else {
        memcpy(&rv, data.pDataBuf, 4); 
    }
    if(rv == 0){
        memcpy(&PublicKey, data.pDataBuf + 8, sizeof(ECCrefPublicKey));
        memcpy(&PrivateKey, data.pDataBuf + 8 + sizeof(ECCrefPublicKey), sizeof(ECCrefPrivateKey));
        Byte2Str(pucPublicKey, PublicKey.x, 2 * ECCref_MAX_LEN);
        Byte2Str(pucPrivateKey, PrivateKey.D, ECCref_MAX_LEN);
    }

    if(data.pDataBuf) {
        free(data.pDataBuf);
    }
    if (rv != 0){
        printf("FHE_SM2Key: failed, rv: %x\n", rv);
        return rv;
    } else {
        printf("FHE_SM2Key: success\n");
    }

	return NFHE_OK;
#endif
}


int FHESdf_Create_Sm2key() {
    int rv;
    rv = check_device_fd();
    if(rv < 0) {
        return NFHE_DEVICE_NOTFOUND;
    }

    unsigned int uiAlgID = SGD_SM2_1;
	unsigned int uiKeyBits = ECCref_MAX_BITS;
    decd_ioctl_ctx data;
    data.inLen = 4 + 4 + 4;
    data.outLen = 8;
    int Command = SDF_CREATE_SM2KEY;
    int len = data.inLen < data.outLen ? data.outLen : data.inLen;
    data.pDataBuf = malloc(len + 1);

    for (int i = 0; i < card_num; i++) {
        memset(data.pDataBuf, 0, len + 1);
        memcpy(data.pDataBuf, &Command, 4);
        memcpy(data.pDataBuf + 4, &uiAlgID, 4);
        memcpy(data.pDataBuf + 4 + 4, &uiKeyBits, 4);

        rv = ioctl(device_fd[i], IOCTL_DECD, &data);
        if (rv < 0) {
            printf("IOCTL IOCTL_DECD: failed\n");
            rv = NFHE_IOCTL_ERROR;
            break;
        } else {
            memcpy(&rv, data.pDataBuf, 4);
            if (rv != 0){
                break;
            }
        }
    }

    if(data.pDataBuf) {
        free(data.pDataBuf);
    }

    if (rv != 0){
        printf("FHESdf_Create_Sm2key: failed, rv: %x\n", rv);
        return rv;
    } else {
        printf("FHESdf_Create_Sm2key: success\n");
    }

    return NFHE_OK;
}


int FHESdf_Backup_Sm2key(char* pucPublicKey, char* pucPrivateKey) {
    ECCrefPublicKey PublicKey;
	ECCrefPrivateKey PrivateKey;

    int rv;
    rv = check_device_fd();
    if(rv < 0) {
        return NFHE_DEVICE_NOTFOUND;
    }

    decd_ioctl_ctx data;
    data.inLen = 4 + 4 + 4;
    data.outLen = 8 + sizeof(ECCrefPublicKey) + sizeof(ECCrefPrivateKey);
    int Command = SDF_BACKUP_SM2KEY;
    int len = data.inLen < data.outLen ? data.outLen : data.inLen;
    data.pDataBuf = malloc(len + 1);
    memset(data.pDataBuf, 0, len + 1);
	memcpy(data.pDataBuf, &Command, 4);

    card_t* usedCard;
    usedCard = (card_t*)nlist_remove(&card_list);
    rv = ioctl(usedCard->fd, IOCTL_DECD, &data);
    nlist_insert(&card_list, &usedCard->node);
    if (rv < 0) {
        printf("IOCTL IOCTL_DECD: failed\n");
        rv = NFHE_IOCTL_ERROR;
    } else {
        memcpy(&rv, data.pDataBuf, 4);
    }

    if(rv == 0){
        memcpy(&PublicKey, data.pDataBuf + 8, sizeof(ECCrefPublicKey));
        memcpy(&PrivateKey, data.pDataBuf + 8 + sizeof(ECCrefPublicKey), sizeof(ECCrefPrivateKey));
        Byte2Str(pucPublicKey, PublicKey.x, 2 * ECCref_MAX_LEN);
        Byte2Str(pucPrivateKey, PrivateKey.D, ECCref_MAX_LEN);
    }

    if(data.pDataBuf) {
        free(data.pDataBuf);
    }

    if (rv != 0){
        printf("FHESdf_Backup_Sm2key: failed, rv: %x\n", rv);
        return rv;
    } else {  
        printf("FHESdf_Backup_Sm2key: success\n");
    }

    return NFHE_OK;
}


int FHESdf_Restore_Sm2key(char* pucPublicKey, char* pucPrivateKey) {
    int rv;
    rv = check_device_fd();
    if(rv < 0) {
        return NFHE_DEVICE_NOTFOUND;
    }

    ECCrefPublicKey PublicKey;
	ECCrefPrivateKey PrivateKey;
	PublicKey.bits = ECCref_MAX_BITS;
	PrivateKey.bits = ECCref_MAX_BITS;
    Str2Byte(PublicKey.x, pucPublicKey);
	Str2Byte(PrivateKey.D, pucPrivateKey);

    decd_ioctl_ctx data;
    data.inLen = 4 + sizeof(ECCrefPublicKey) + sizeof(ECCrefPrivateKey);
    data.outLen = 8;
    int Command = SDF_RESTORE_SM2KEY;
    int len = data.inLen < data.outLen ? data.outLen : data.inLen;
    data.pDataBuf = malloc(len + 1);

    for (int i = 0; i < card_num; i++) {
        memset(data.pDataBuf, 0, len + 1);
        memcpy(data.pDataBuf, &Command, 4);
        memcpy(data.pDataBuf + 4, &PublicKey, sizeof(ECCrefPublicKey));
        memcpy(data.pDataBuf + 4 + sizeof(ECCrefPublicKey), &PrivateKey, sizeof(ECCrefPrivateKey));

        rv = ioctl(device_fd[i], IOCTL_DECD, &data);
        if (rv < 0) {
            printf("IOCTL IOCTL_DECD: failed\n");
            rv = NFHE_IOCTL_ERROR;
            break;
        } else {
            memcpy(&rv, data.pDataBuf, 4);
            if (rv != 0){
                break;
            }
        }
    }

    if(data.pDataBuf) {
        free(data.pDataBuf);
    }

    if (rv != 0){
        printf("FHESdf_Restore_Sm2key: failed, rv: %x\n", rv);
        return rv;
    } else {
        printf("FHESdf_Restore_Sm2key: success\n");
    }

    return NFHE_OK;
}


int SDF_Sm2_Enc(unsigned char *pucData, unsigned int uiDataLength, ECCCipher *pucEncData) {
    int rv;

    decd_ioctl_ctx data;
    data.inLen = 4 + 4 + uiDataLength;
    data.outLen = 8 + (sizeof(ECCCipher) - sizeof(pucEncData->C) + uiDataLength + 4);
    int Command = SDF_SM2_ENC;
    int len = data.inLen < data.outLen ? data.outLen : data.inLen;
    data.pDataBuf = malloc(len + 1);
	memset(data.pDataBuf, 0, len + 1);
	memcpy(data.pDataBuf, &Command, 4);
    memcpy(data.pDataBuf + 4, &uiDataLength, 4);
    memcpy(data.pDataBuf + 4 + 4, pucData, uiDataLength);

    card_t* usedCard;
    usedCard = (card_t*)nlist_remove(&card_list);
    rv = ioctl(usedCard->fd, IOCTL_DECD, &data);
    nlist_insert(&card_list, &usedCard->node);
    if (rv < 0) {
        printf("IOCTL IOCTL_DECD: failed\n");
        rv = NFHE_IOCTL_ERROR;
    } else {
        memcpy(&rv, data.pDataBuf, 4);
    }

    if(rv == 0){
        memcpy(pucEncData, data.pDataBuf + 8, (sizeof(ECCCipher) - sizeof(pucEncData->C) + uiDataLength));
    }

    if(data.pDataBuf) {
        free(data.pDataBuf);
    }

    if (rv != 0){
        printf("SDF_Sm2_Enc: failed, rv: %x\n", rv);
        return rv;
    } else {
        printf("SDF_Sm2_Enc: success\n");
    }

    return NFHE_OK;
}


int FHESdf_Sm2_Enc(char* pucData, unsigned int uiDataLength, char* pucEnc) {
    int rv;
    rv = check_device_fd();
    if(rv < 0) {
        return NFHE_DEVICE_NOTFOUND;
    }

    unsigned char pucDataByte[FHE_CYPHER_BYTES];
    Str2Byte(pucDataByte, pucData);
    ECCCipher ec;
    TestECCCipher tec;

    SDF_Sm2_Enc(pucDataByte, uiDataLength, &ec);

    memcpy(tec.x, ec.x, 32);
	memcpy(tec.y, ec.y, 32);
	memcpy(tec.M, ec.M, 32);
	memcpy(tec.C, ec.C, uiDataLength);

	Byte2Str(pucEnc, (unsigned char*)&tec, 96 + uiDataLength);

    return NFHE_OK;
}


int SDF_Sm2_Dec(ECCCipher *pucEncData, unsigned char *pucData, unsigned int *uiDataLength) {
    int rv;

    decd_ioctl_ctx data;
    data.inLen = 4 + (sizeof(ECCCipher) - sizeof(pucEncData->C) + pucEncData->L);
    data.outLen = 8 + *uiDataLength;
    int Command = SDF_SM2_DEC;
    int len = data.inLen < data.outLen ? data.outLen : data.inLen;
    data.pDataBuf = malloc(len + 1);
	memset(data.pDataBuf, 0, len + 1);
	memcpy(data.pDataBuf, &Command, 4);
    memcpy(data.pDataBuf + 4, pucEncData, (sizeof(ECCCipher) - sizeof(pucEncData->C) + pucEncData->L));

    card_t* usedCard;
    usedCard = (card_t*)nlist_remove(&card_list);
    rv = ioctl(usedCard->fd, IOCTL_DECD, &data);
    nlist_insert(&card_list, &usedCard->node);
    if (rv < 0) {
        printf("IOCTL IOCTL_DECD: failed\n");
        rv = NFHE_IOCTL_ERROR;
    } else {
        memcpy(&rv, data.pDataBuf, 4);
    }

    if(rv == 0){
        memcpy(pucData, data.pDataBuf + 8, *uiDataLength);
    }

    if(data.pDataBuf) {
        free(data.pDataBuf);
    }

    if (rv != 0){
        printf("FHESdf_Sm2_Dec: failed, rv: %x\n", rv);
        return rv;
    } else {
        printf("FHESdf_Sm2_Dec: success\n");
    }

    return NFHE_OK;
}


int FHESdf_Sm2_Dec(char* pucEnc, unsigned int uiDataLength, char* pucData) {
    int rv;
    rv = check_device_fd();
    if(rv < 0) {
        return NFHE_DEVICE_NOTFOUND;
    }

    unsigned char pucDataByte[FHE_CYPHER_BYTES];
	ECCCipher PEnc;
	TestECCCipher tec;
    Str2Byte((unsigned char*)(&tec), pucEnc);
	memcpy(PEnc.x, tec.x, 32);
	memcpy(PEnc.y, tec.y, 32);
	memcpy(PEnc.M, tec.M, 32);
	memcpy(PEnc.C, tec.C, uiDataLength);

    PEnc.L = uiDataLength;

    SDF_Sm2_Dec(&PEnc, pucDataByte, &uiDataLength);

    Byte2Str(pucData, pucDataByte, uiDataLength);

    return NFHE_OK;
}


int SDF_HashInit_Without_Key(
    int fd,
	unsigned int uiAlgID,
	unsigned char *pucID,
	unsigned int uiIDLength)
{
    int rv;

    decd_ioctl_ctx data;
    if(uiAlgID == SGD_SM3_ID) {
        data.inLen = 4 + 4 + uiIDLength + 4;
        data.outLen = 8;
        int Command = SDF_HASHINIT_WITHOUT_KEY;
        int len = data.inLen < data.outLen ? data.outLen : data.inLen;
        data.pDataBuf = malloc(len + 1);
        memset(data.pDataBuf, 0, len + 1);
        memcpy(data.pDataBuf, &Command, 4);
        memcpy(data.pDataBuf + 4, &uiAlgID, 4);
        memcpy(data.pDataBuf + 4 + 4, &uiIDLength, 4);
        memcpy(data.pDataBuf + 4 + 4 + 4, pucID, uiIDLength);
    } else {
        data.inLen = 4 + 4;
        data.outLen = 8;
        int Command = SDF_HASHINIT_WITHOUT_KEY;
        int len = data.inLen < data.outLen ? data.outLen : data.inLen;
        data.pDataBuf = malloc(len + 1);
        memset(data.pDataBuf, 0, len + 1);
        memcpy(data.pDataBuf, &Command, 4);
        memcpy(data.pDataBuf + 4, &uiAlgID, 4);
    }
    
    rv = ioctl(fd, IOCTL_DECD, &data);

    if (rv < 0) {
        printf("IOCTL IOCTL_DECD: failed\n");
        rv = NFHE_IOCTL_ERROR;
    } else {
        memcpy(&rv, data.pDataBuf, 4);
    }

    if(data.pDataBuf) {
        free(data.pDataBuf);
    }

    if (rv != 0){
        printf("SDF_HashInit_Without_Key: failed, rv: %x\n", rv);
        return rv;
    } else {
        printf("SDF_HashInit_Without_Key: success\n");
    }

    return NFHE_OK;
}


int SDF_HashUpdate(
    int fd,
	unsigned char *pucData,
	unsigned int uiDataLength
	)
{
    int rv;

    decd_ioctl_ctx data;
    data.inLen = 4 + 4 + uiDataLength;
    data.outLen = 8;
    int Command = SDF_HASHUPDATE;
    int len = data.inLen < data.outLen ? data.outLen : data.inLen;
    data.pDataBuf = malloc(len + 1);
    memset(data.pDataBuf, 0, len + 1);
    memcpy(data.pDataBuf, &Command, 4);
    memcpy(data.pDataBuf + 4, &uiDataLength, 4);
    memcpy(data.pDataBuf + 4 + 4, pucData, uiDataLength);
    
    rv = ioctl(fd, IOCTL_DECD, &data);

    if (rv < 0) {
        printf("IOCTL IOCTL_DECD: failed\n");
        rv = NFHE_IOCTL_ERROR;
    } else {
        memcpy(&rv, data.pDataBuf, 4);
    }

    if(data.pDataBuf) {
        free(data.pDataBuf);
    }
    if (rv != 0){
        printf("SDF_HashUpdate: failed, rv: %x\n", rv);
        return rv;
    } else {
        printf("SDF_HashUpdate: success\n");
    }

    return NFHE_OK;
}


int SDF_HashFinal(
    int fd,
	unsigned char *pucHash,
	unsigned int  *puiHashLength)
{
    int rv;

	decd_ioctl_ctx data;
    data.inLen = 4 + 4;
    data.outLen = 8 + 32;
    int Command = SDF_HASHFINAL;
    int len = data.inLen < data.outLen ? data.outLen : data.inLen;
    data.pDataBuf = malloc(len + 1);
    memset(data.pDataBuf, 0, len + 1);
    memcpy(data.pDataBuf, &Command, 4);

    *puiHashLength = 32;
    
    rv = ioctl(fd, IOCTL_DECD, &data);

    if (rv < 0) {
        printf("IOCTL IOCTL_DECD: failed\n");
        rv = NFHE_IOCTL_ERROR;
    } else {
        memcpy(&rv, data.pDataBuf, 4);
    }
    if(rv == 0) {
        memcpy(pucHash, data.pDataBuf + 8, *puiHashLength);
    }

    if(data.pDataBuf) {
        free(data.pDataBuf);
    }
    if (rv != 0){
        printf("SDF_HashFinal: failed, rv: %x\n", rv);
        return rv;
    } else {
        printf("SDF_HashFinal: success\n");
    }

    return NFHE_OK;
}


int NFHE_SM3_ID_Without_Key_INTERNAL(
    int fd,
	char *pucID,
	unsigned int IdLength,
	char *In,
	unsigned int InLength,
	char *Out
)
{
	int dwRet, n, idLen;
	unsigned char * pucDataByte;
	unsigned char * pMessage;
	unsigned char pID[16];
	unsigned char pResult[32];

	unsigned int outlen;

	idLen = IdLength / 2;
	n = InLength / 2;

	pucDataByte = (unsigned char *)malloc(n);

	Str2Byte(pucDataByte, In);

	Str2Byte(pID, pucID);

	if ((dwRet = SDF_HashInit_Without_Key(fd, SGD_SM3_ID, pID, idLen)) != 0)
	{
		free(pucDataByte);
		return dwRet;
	}

	pMessage = pucDataByte;
	while (n > FHE_SM3_INPUT_MAX) {
		if ((dwRet = SDF_HashUpdate(fd, pMessage, FHE_SM3_INPUT_MAX)) != 0)
		{
			free(pucDataByte);
			return dwRet;
		}
		pMessage += 1024;
		n -= 1024;
	}
	if (n > 0)
		if ((dwRet = SDF_HashUpdate(fd, pMessage, n)) != 0)
		{
			free(pucDataByte);
			return dwRet;
		}

	if ((dwRet = SDF_HashFinal(fd, pResult, &outlen)) != 0)
	{
		free(pucDataByte);
		return dwRet;
	}


	Byte2Str(Out, pResult, outlen);

	free(pucDataByte);
	return 0;
}


int SDF_ExternalSign_ECC_Without_Key(
    int fd,
	unsigned int uiAlgID,
	unsigned char *pucData,
	unsigned int  uiDataLength,
	ECCSignature *pucSignature
	)
{
	int rv;

	decd_ioctl_ctx data;
    data.inLen = 4 + 4 + uiDataLength + 4;
    data.outLen = 8 + sizeof(ECCSignature);
    int Command = SDF_EXTERNALSIGN_ECC_WITHOUT_KEY;
    int len = data.inLen < data.outLen ? data.outLen : data.inLen;
    data.pDataBuf = malloc(len + 1);
    memset(data.pDataBuf, 0, len + 1);
    memcpy(data.pDataBuf, &Command, 4);
    memcpy(data.pDataBuf + 4, &uiAlgID, 4);
    memcpy(data.pDataBuf + 4 + 4, &uiDataLength, 4);
    memcpy(data.pDataBuf + 4 + 4 + 4, pucData, uiDataLength);
    
    rv = ioctl(fd, IOCTL_DECD, &data);

    if (rv < 0) {
        printf("IOCTL IOCTL_DECD: failed\n");
        rv = NFHE_IOCTL_ERROR;
    } else {
        memcpy(&rv, data.pDataBuf, 4);
    }
    if(rv == 0) {
        memcpy(pucSignature, data.pDataBuf + 8, sizeof(ECCSignature));
    }

    if(data.pDataBuf) {
        free(data.pDataBuf);
    }
    if (rv != 0){
        printf("SDF_ExternalSign_ECC_Without_Key: failed, rv: %x\n", rv);
        return rv;
    } else {
        printf("SDF_ExternalSign_ECC_Without_Key: success\n");
    }

    return NFHE_OK;
}


int FHE_SM2Sign_raw_Without_Key(
    int fd,
	char *pucData,
	char *pucSignature
	)
{
	unsigned char pucDataByte[FHE_SM2_INPUT_MAX];
	ECCSignature Sm2Signature;

	Str2Byte(pucDataByte, pucData);

	SDF_ExternalSign_ECC_Without_Key(fd, SGD_SM2_1, pucDataByte, 32, &Sm2Signature);

	Byte2Str(pucSignature, Sm2Signature.r, 2 * ECCref_MAX_LEN);

	return NFHE_OK;
}


int FHESdf_Sm2_Sign(char* pucID, unsigned int IdLength, char* pucData, unsigned int uiDataLength, char* pucSignature) {
    int rv;

    char MessageHashStr[65];

    if (uiDataLength > FHE_SM2_INPUT_MAX)
		return NFHE_PARAMETERERR;

    card_t* usedCard;
    usedCard = (card_t*)nlist_remove(&card_list);
    
    rv = NFHE_SM3_ID_Without_Key_INTERNAL(usedCard->fd, pucID, IdLength, pucData, uiDataLength, MessageHashStr);
    if (rv != 0) {
        nlist_insert(&card_list, &usedCard->node);
        return NFHE_SM3_ERROR;
    }
		
    rv = FHE_SM2Sign_raw_Without_Key(usedCard->fd, MessageHashStr, pucSignature);

    nlist_insert(&card_list, &usedCard->node);

    return rv;
}


int SDF_ExternalVerify_ECC_Without_Key(
    int fd,
	unsigned int uiAlgID,
	unsigned char *pucDataInput,
	unsigned int  uiInputLength,
	ECCSignature *pucSignature)
{
    int rv = 0;

    decd_ioctl_ctx data;
    data.inLen = 4 + 4 + uiInputLength + 4 + sizeof(ECCSignature);
    data.outLen = 8;
    int Command = SDF_EXTERNALVERIFY_ECC_WITHOUT_KEY;
    int len = data.inLen < data.outLen ? data.outLen : data.inLen;
    data.pDataBuf = malloc(len + 1);
    memset(data.pDataBuf, 0, len + 1);
    memcpy(data.pDataBuf, &Command, 4);
    memcpy(data.pDataBuf + 4, &uiAlgID, 4);
    memcpy(data.pDataBuf + 4 + 4, &uiInputLength, 4);
    memcpy(data.pDataBuf + 4 + 4 + 4, pucDataInput, uiInputLength);
    memcpy(data.pDataBuf + 4 + 4 + 4 + uiInputLength, pucSignature, sizeof(ECCSignature));
    
    rv = ioctl(fd, IOCTL_DECD, &data);

    if (rv < 0) {
        printf("IOCTL IOCTL_DECD: failed\n");
        rv = NFHE_IOCTL_ERROR;
    } else {
        memcpy(&rv, data.pDataBuf, 4);
    }

    if(data.pDataBuf) {
        free(data.pDataBuf);
    }
    if (rv != 0){
        printf("SDF_ExternalVerify_ECC_Without_Key: failed, rv: %x\n", rv);
        return rv;
    } else {
        printf("SDF_ExternalVerify_ECC_Without_Key: success\n");
    }

    return NFHE_OK;
}


int FHE_SM2Verify_raw_Without_Key(
    int fd,
	char *pucData,
	char *pucSignature)
{
	unsigned char pucDataByte[32];
	ECCSignature Sm2Signature;

	Str2Byte(Sm2Signature.r, pucSignature);
	Str2Byte(pucDataByte, pucData);

	return SDF_ExternalVerify_ECC_Without_Key(fd, SGD_SM2_1, pucDataByte, 32, &Sm2Signature);
}


int FHESdf_Sm2_Verify(char* pucID, unsigned int IdLength, char* pucData, unsigned int uiDataLength, char* pucSignature) {
    int rv;

    char MessageHashStr[65];

	if (uiDataLength > FHE_SM2_INPUT_MAX)
		return NFHE_PARAMETERERR;

    card_t* usedCard;
    usedCard = (card_t*)nlist_remove(&card_list);

    rv = NFHE_SM3_ID_Without_Key_INTERNAL(usedCard->fd, pucID, IdLength, pucData, uiDataLength, MessageHashStr);
	if (rv != 0) {
        nlist_insert(&card_list, &usedCard->node);
        return NFHE_SM3_ERROR;
    }
		
	rv = FHE_SM2Verify_raw_Without_Key(usedCard->fd, MessageHashStr, pucSignature);

    nlist_insert(&card_list, &usedCard->node);

    return rv;
}


// ********************************************* compute.h *********************************************
int NFHE_Encrypt(unsigned int pucDataInput, unsigned char *pucDataOutput)
{
    int rv;
    rv = check_device_fd();
    if(rv < 0) {
        return NFHE_DEVICE_NOTFOUND;
    }

    unsigned char cache[128];
    memset(cache, 0, 128);
    *(unsigned int *)cache = pucDataInput;

    card_t* usedCard;
    usedCard = (card_t*)nlist_remove(&card_list);
    rv = ioctl(usedCard->fd, IOCTL_FHE_ENC, cache);
    nlist_insert(&card_list, &usedCard->node);
    if (rv < 0) {
        printf("IOCTL NFHE_Encrypt failed, %d\n", rv);
    } else {
        memcpy(pucDataOutput, cache, FHE_CYPHER_BYTES);
    }

    return NFHE_OK;
}


int NFHE_Decrypt(unsigned char *pucDataInput, unsigned int *pucDataOutput)
{
    int rv;
    rv = check_device_fd();
    if(rv < 0) {
        return NFHE_DEVICE_NOTFOUND;
    }

    card_t* usedCard;
    usedCard = (card_t*)nlist_remove(&card_list);
    rv = ioctl(usedCard->fd, IOCTL_FHE_DEC, pucDataInput);
    nlist_insert(&card_list, &usedCard->node);
    if (rv < 0) {
        printf("IOCTL NFHE_Decrypt: failed\n");
        rv = NFHE_IOCTL_ERROR;
    } else {
        *pucDataOutput = *(unsigned int *)pucDataInput;
    }

	return NFHE_OK;
}


int check_auth(unsigned int fd, unsigned int uiKeyIndex, char* pFhe_Auth)
{
    unsigned char pbData[16];
	Str2Bn(pbData, pFhe_Auth);

	int rv;

    decd_ioctl_ctx data;
    data.inLen = 4 + 4 + 16;
    data.outLen = 8;
    int Command = KMG_COMPARE_SM1AUTH;
    int len = data.inLen < data.outLen ? data.outLen : data.inLen;
    data.pDataBuf = malloc(len + 1);
    memset(data.pDataBuf, 0, data.inLen + 1);
	memcpy(data.pDataBuf, &Command, 4);
    memcpy(data.pDataBuf + 4, &uiKeyIndex, 4);
    memcpy(data.pDataBuf + 4 + 4, pbData, 16);

    rv = ioctl(fd, IOCTL_DECD, &data);
    if (rv < 0) {
        printf("IOCTL IOCTL_DECD: failed\n");
        rv = NFHE_IOCTL_ERROR;
    } else {
        memcpy(&rv, data.pDataBuf, 4);
    }

    if(data.pDataBuf) {
        free(data.pDataBuf);
    }
        
    if (rv != 0){
        rv = NFHE_SM1_BACKUP_ERROR;
        return rv;
    }

    return NFHE_OK;
}


int check_type(unsigned char* pDecrypteddata, unsigned int type)
{
    int extractedTypeValue = pDecrypteddata[3] * 10 + pDecrypteddata[7];
	if (extractedTypeValue != type)
	{
		return NFHE_DEC_TYPE_ERROR;   
	}
    return 0;
}


void setRandom(unsigned char *data) {
    srand((unsigned)time(NULL));
	int ranNum = rand();
    *data = ranNum & 0b11111111;
}


int Sm1_Index_EncDec(unsigned int uiKeyIndex, unsigned char* pPlaindata, unsigned int uByteLen, unsigned char mode, unsigned char* pbEncrypteddata)
{
    int rv;

    sm1_ioctl_ctx ctx;
    // mode 1 加密 0 解密
    ctx.ssx_cmd = mode;
    ctx.inputLength = uByteLen;
    ctx.inbuf = malloc(ctx.inputLength + 1);
    memset(ctx.inbuf, 0, ctx.inputLength + 1);
    memcpy(ctx.inbuf, pPlaindata, ctx.inputLength);

    ctx.outputLength = uByteLen;
    ctx.outbuf = malloc(ctx.outputLength + 1);
    memset(ctx.outbuf, 0, ctx.outputLength + 1);

    card_t* usedCard;
    usedCard = (card_t*)nlist_remove(&card_list);

    write_usr_reg(usedCard->fd, 0x8300, uiKeyIndex & 0b11111111);
	write_usr_reg(usedCard->fd, 0x8310, uByteLen);
	write_usr_reg(usedCard->fd, 0x80FC, 0b00000);
    write_usr_reg(usedCard->fd, 0x8320, 0b00001);

    rv = ioctl(usedCard->fd, IOCTL_NFHE_DMA_SM1, &ctx);
    nlist_insert(&card_list, &usedCard->node);

    if (rv < 0) {
        printf("IOCTL IOCTL_NFHE_DMA_SM1: failed\n");
        rv = NFHE_IOCTL_ERROR;
    } else {
        memcpy(pbEncrypteddata, ctx.outbuf, ctx.outputLength);
    }

    if(ctx.inbuf) {
        free(ctx.inbuf);
    }
        
    if(ctx.outbuf) {
        free(ctx.outbuf);
    } 

    if(rv > 0) {
        rv = NFHE_OK;
    }
	return rv;
}


int Sm1_Index_EncDecEx(unsigned int nCount, unsigned int* pKeyIndex, unsigned char* pPlaindata, unsigned int uByteLen, unsigned char mode, unsigned char* pbEncrypteddata)
{
    int rv;

    sm1_ioctl_ctx ctx;
    // mode 1 加密 0 解密
    ctx.ssx_cmd = mode;
    ctx.inputLength = uByteLen;
    ctx.inbuf = malloc(ctx.inputLength + 1);
    memset(ctx.inbuf, 0, ctx.inputLength + 1);
    memcpy(ctx.inbuf, pPlaindata, ctx.inputLength);

    ctx.outputLength = uByteLen;
    ctx.outbuf = malloc(ctx.outputLength + 1);
    memset(ctx.outbuf, 0, ctx.outputLength + 1);

    card_t* usedCard;
    usedCard = (card_t*)nlist_remove(&card_list);

    for (int i = 0; i < nCount; ++i) {
        write_usr_reg(usedCard->fd, 0x8300, pKeyIndex[i] & 0b11111111);
	}
	write_usr_reg(usedCard->fd, 0x8310, uByteLen / nCount);

	write_usr_reg(usedCard->fd, 0x80FC, 0b00000);
    write_usr_reg(usedCard->fd, 0x8320, nCount);

    rv = ioctl(usedCard->fd, IOCTL_NFHE_DMA_SM1, &ctx);
    nlist_insert(&card_list, &usedCard->node);

    if (rv < 0) {
        printf("IOCTL IOCTL_NFHE_DMA_SM1: failed\n");
        rv = NFHE_IOCTL_ERROR;
    } else {
        memcpy(pbEncrypteddata, ctx.outbuf, ctx.outputLength);
    }

    if(ctx.inbuf) {
        free(ctx.inbuf);
    }
        
    if(ctx.outbuf) {
        free(ctx.outbuf);
    } 

    if(rv > 0) {
        rv = NFHE_OK;
    }
	return rv;
}


int Sm1_InKey_EncDec(char * pPlaindata, unsigned int uByteLen, unsigned int mode, char * pbEncrypteddata) {
    int rv;
    rv = check_device_fd();
    if(rv < 0) {
        return NFHE_DEVICE_NOTFOUND;
    }

    // 默认使用的密钥索引
    const int uiKeyIndex = 1;

    rv = Sm1_Index_EncDec(uiKeyIndex, pPlaindata, uByteLen, mode, pbEncrypteddata);
    return rv;
}


int Sm1_WithKey_EncDec(char * pPlaindata, unsigned int uByteLen, char* pKey, unsigned int mode, char * pbEncrypteddata) {
    int rv;
    rv = check_device_fd();
    if(rv < 0) {
        return NFHE_DEVICE_NOTFOUND;
    }

    // 默认使用的密钥索引
    const int uiKeyIndex = 1;

    // 恢复密钥（以明文方式）
    rv = FHEKmg_Restore_Sm1key_PLAIN(uiKeyIndex, pKey);
    if(rv < 0) {
        return rv;
    }

	char* pbData;
    char* pbEncData;
	unsigned int ByteLen;

	ByteLen = uByteLen / 2;
	pbData = (char*)malloc(ByteLen);
	pbEncData = (char*)malloc(ByteLen);

	Str2Byte(pbData, pPlaindata);

    rv = Sm1_Index_EncDec(uiKeyIndex, pbData, ByteLen, mode, pbEncData);

    Byte2Str(pbEncrypteddata, pbEncData, ByteLen);

	free(pbData);
	free(pbEncData);
    
    return rv;
}


int PEncS32(int Plaindata, unsigned int uiKeyIndex, unsigned char* pEncrypteddata)
{
    int rv;
    rv = check_device_fd();
    if(rv < 0) {
        return NFHE_DEVICE_NOTFOUND;
    }

    long long data = (long long)Plaindata;
    unsigned char PlaindataWithType[16];
    memset(PlaindataWithType, 0, sizeof(PlaindataWithType));
    setRandom(&PlaindataWithType[0]);
	PlaindataWithType[3] = 0;
    PlaindataWithType[7] = 0;
    PlaindataWithType[8] = data >> 56 & 0b11111111;
    PlaindataWithType[9] = data >> 48 & 0b11111111;
    PlaindataWithType[10] = data >> 40 & 0b11111111;
    PlaindataWithType[11] = data >> 32 & 0b11111111;
    PlaindataWithType[12] = data >> 24 & 0b11111111;
    PlaindataWithType[13] = data >> 16 & 0b11111111;
    PlaindataWithType[14] = data >> 8 & 0b11111111;
    PlaindataWithType[15] = data & 0b11111111;
    
	rv = Sm1_Index_EncDec(uiKeyIndex, PlaindataWithType, 16, 1, pEncrypteddata);

    return rv;
}


int PEnc32(unsigned int Plaindata, unsigned int uiKeyIndex, unsigned char* pEncrypteddata)
{
    int rv;
    rv = check_device_fd();
    if(rv < 0) {
        return NFHE_DEVICE_NOTFOUND;
    }

    unsigned long long data = (unsigned long long)Plaindata;
    unsigned char PlaindataWithType[16];
    memset(PlaindataWithType, 0, sizeof(PlaindataWithType));
    setRandom(&PlaindataWithType[0]);
	PlaindataWithType[3] = 4;
    PlaindataWithType[7] = 0;
    PlaindataWithType[8] = data >> 56 & 0b11111111;
    PlaindataWithType[9] = data >> 48 & 0b11111111;
    PlaindataWithType[10] = data >> 40 & 0b11111111;
    PlaindataWithType[11] = data >> 32 & 0b11111111;
    PlaindataWithType[12] = data >> 24 & 0b11111111;
    PlaindataWithType[13] = data >> 16 & 0b11111111;
    PlaindataWithType[14] = data >> 8 & 0b11111111;
    PlaindataWithType[15] = data & 0b11111111;
    
	rv = Sm1_Index_EncDec(uiKeyIndex, PlaindataWithType, 16, 1, pEncrypteddata);

    return rv;
}


int PEncS64(long long Plaindata, unsigned int uiKeyIndex, unsigned char* pEncrypteddata)
{
    int rv;
    rv = check_device_fd();
    if(rv < 0) {
        return NFHE_DEVICE_NOTFOUND;
    }

    unsigned char PlaindataWithType[16];
    memset(PlaindataWithType, 0, sizeof(PlaindataWithType));
    setRandom(&PlaindataWithType[0]);
	PlaindataWithType[3] = 0;
    PlaindataWithType[7] = 1;
    PlaindataWithType[8] = Plaindata >> 56 & 0b11111111;
    PlaindataWithType[9] = Plaindata >> 48 & 0b11111111;
    PlaindataWithType[10] = Plaindata >> 40 & 0b11111111;
    PlaindataWithType[11] = Plaindata >> 32 & 0b11111111;
    PlaindataWithType[12] = Plaindata >> 24 & 0b11111111;
    PlaindataWithType[13] = Plaindata >> 16 & 0b11111111;
    PlaindataWithType[14] = Plaindata >> 8 & 0b11111111;
    PlaindataWithType[15] = Plaindata & 0b11111111;
    
	rv = Sm1_Index_EncDec(uiKeyIndex, PlaindataWithType, 16, 1, pEncrypteddata);

    return rv;
}


int PEnc64(unsigned long long Plaindata, unsigned int uiKeyIndex, unsigned char* pEncrypteddata)
{
    int rv;
    rv = check_device_fd();
    if(rv < 0) {
        return NFHE_DEVICE_NOTFOUND;
    }

    unsigned char PlaindataWithType[16];
    memset(PlaindataWithType, 0, sizeof(PlaindataWithType));
    setRandom(&PlaindataWithType[0]);
	PlaindataWithType[3] = 4;
    PlaindataWithType[7] = 1;
    PlaindataWithType[8] = Plaindata >> 56 & 0b11111111;
    PlaindataWithType[9] = Plaindata >> 48 & 0b11111111;
    PlaindataWithType[10] = Plaindata >> 40 & 0b11111111;
    PlaindataWithType[11] = Plaindata >> 32 & 0b11111111;
    PlaindataWithType[12] = Plaindata >> 24 & 0b11111111;
    PlaindataWithType[13] = Plaindata >> 16 & 0b11111111;
    PlaindataWithType[14] = Plaindata >> 8 & 0b11111111;
    PlaindataWithType[15] = Plaindata & 0b11111111;
    
	rv = Sm1_Index_EncDec(uiKeyIndex, PlaindataWithType, 16, 1, pEncrypteddata);

    return rv;
}

int PEncF32(float Plaindata, unsigned int uiKeyIndex, unsigned char* pEncrypteddata)
{
    int rv;
    rv = check_device_fd();
    if(rv < 0) {
        return NFHE_DEVICE_NOTFOUND;
    }

    union FloatToBytes {
		float f;
		unsigned char bytes[4];
	}converter;
	converter.f = Plaindata;

    unsigned char PlaindataWithType[16];
    memset(PlaindataWithType, 0, sizeof(PlaindataWithType));
    setRandom(&PlaindataWithType[0]);
	PlaindataWithType[3] = 1;
    PlaindataWithType[7] = 0;
    PlaindataWithType[12] = converter.bytes[3] & 0b11111111;
    PlaindataWithType[13] = converter.bytes[2] & 0b11111111;
    PlaindataWithType[14] = converter.bytes[1] & 0b11111111;
    PlaindataWithType[15] = converter.bytes[0] & 0b11111111;
    
	rv = Sm1_Index_EncDec(uiKeyIndex, PlaindataWithType, 16, 1, pEncrypteddata);

    return rv;
}

int PEncF64(double Plaindata, unsigned int uiKeyIndex, unsigned char* pEncrypteddata)
{
    int rv;
    rv = check_device_fd();
    if(rv < 0) {
        return NFHE_DEVICE_NOTFOUND;
    }

    union DoubleToBytes {
		double d;
		unsigned char bytes[8];
	}converter;
	converter.d = Plaindata;

    unsigned char PlaindataWithType[16];
    memset(PlaindataWithType, 0, sizeof(PlaindataWithType));
    setRandom(&PlaindataWithType[0]);
	PlaindataWithType[3] = 1;
    PlaindataWithType[7] = 1;
    PlaindataWithType[8] = converter.bytes[7] & 0b11111111;
    PlaindataWithType[9] = converter.bytes[6] & 0b11111111;
    PlaindataWithType[10] = converter.bytes[5] & 0b11111111;
    PlaindataWithType[11] = converter.bytes[4] & 0b11111111;
    PlaindataWithType[12] = converter.bytes[3] & 0b11111111;
    PlaindataWithType[13] = converter.bytes[2] & 0b11111111;
    PlaindataWithType[14] = converter.bytes[1] & 0b11111111;
    PlaindataWithType[15] = converter.bytes[0] & 0b11111111;
    
	rv = Sm1_Index_EncDec(uiKeyIndex, PlaindataWithType, 16, 1, pEncrypteddata);

    return rv;
}


int PDecS32(unsigned char* pEncrypteddata, unsigned int uiKeyIndex, char* pFhe_Auth, int* pPlaindata)
{
    int rv;
    rv = check_device_fd();
    if(rv < 0) {
        return NFHE_DEVICE_NOTFOUND;
    }

    unsigned char pDecrypteddata[16];

    card_t* usedCard;
    usedCard = (card_t*)nlist_remove(&card_list);
    rv = check_auth(usedCard->fd, uiKeyIndex, pFhe_Auth);
    if(rv != 0){
        nlist_insert(&card_list, &usedCard->node);
        return rv;
    }
    nlist_insert(&card_list, &usedCard->node);

	rv = Sm1_Index_EncDec(uiKeyIndex, pEncrypteddata, 16, 0, pDecrypteddata);

	rv = check_type(pDecrypteddata, INTS32);
    if(rv == 0) {
        unsigned long long data = (unsigned long long)pDecrypteddata[8] << 56 |
		(unsigned long long)pDecrypteddata[9] << 48 |
		(unsigned long long)pDecrypteddata[10] << 40 |
		(unsigned long long)pDecrypteddata[11] << 32 |
		(unsigned long long)pDecrypteddata[12] << 24 |
		(unsigned long long)pDecrypteddata[13] << 16 |
		(unsigned long long)pDecrypteddata[14] << 8 |
		(unsigned long long)pDecrypteddata[15];
	    *pPlaindata = *((int*)&data);
    }

	return rv;
}


int PDec32(unsigned char* pEncrypteddata, unsigned int uiKeyIndex, char* pFhe_Auth, unsigned int* pPlaindata)
{
    int rv;
    rv = check_device_fd();
    if(rv < 0) {
        return NFHE_DEVICE_NOTFOUND;
    }

    unsigned char pDecrypteddata[16];

    card_t* usedCard;
    usedCard = (card_t*)nlist_remove(&card_list);
    rv = check_auth(usedCard->fd, uiKeyIndex, pFhe_Auth);
    if(rv != 0){
        nlist_insert(&card_list, &usedCard->node);
        return rv;
    }
    nlist_insert(&card_list, &usedCard->node);

	rv = Sm1_Index_EncDec(uiKeyIndex, pEncrypteddata, 16, 0, pDecrypteddata);

	rv = check_type(pDecrypteddata, INT32);
    if(rv == 0) {
        unsigned long long data = (unsigned long long)pDecrypteddata[8] << 56 |
		(unsigned long long)pDecrypteddata[9] << 48 |
		(unsigned long long)pDecrypteddata[10] << 40 |
		(unsigned long long)pDecrypteddata[11] << 32 |
		(unsigned long long)pDecrypteddata[12] << 24 |
		(unsigned long long)pDecrypteddata[13] << 16 |
		(unsigned long long)pDecrypteddata[14] << 8 |
		(unsigned long long)pDecrypteddata[15];
	    *pPlaindata = *((unsigned int*)&data);
    }

	return rv;
}

int PDecS64(unsigned char* pEncrypteddata, unsigned int uiKeyIndex, char* pFhe_Auth, long long* pPlaindata)
{
    int rv;
    rv = check_device_fd();
    if(rv < 0) {
        return NFHE_DEVICE_NOTFOUND;
    }

    unsigned char pDecrypteddata[16];

    card_t* usedCard;
    usedCard = (card_t*)nlist_remove(&card_list);
    rv = check_auth(usedCard->fd, uiKeyIndex, pFhe_Auth);
    if(rv != 0){
        nlist_insert(&card_list, &usedCard->node);
        return rv;
    }
    nlist_insert(&card_list, &usedCard->node);

	rv = Sm1_Index_EncDec(uiKeyIndex, pEncrypteddata, 16, 0, pDecrypteddata);
    
	rv = check_type(pDecrypteddata, INTS64);
    if(rv == 0) {
        unsigned long long data = (unsigned long long)pDecrypteddata[8] << 56 |
		(unsigned long long)pDecrypteddata[9] << 48 |
		(unsigned long long)pDecrypteddata[10] << 40 |
		(unsigned long long)pDecrypteddata[11] << 32 |
		(unsigned long long)pDecrypteddata[12] << 24 |
		(unsigned long long)pDecrypteddata[13] << 16 |
		(unsigned long long)pDecrypteddata[14] << 8 |
		(unsigned long long)pDecrypteddata[15];
	    *pPlaindata = *((long long*)&data);
    }

	return rv;
}


int PDec64(unsigned char* pEncrypteddata, unsigned int uiKeyIndex, char* pFhe_Auth, unsigned long long* pPlaindata)
{
    int rv;
    rv = check_device_fd();
    if(rv < 0) {
        return NFHE_DEVICE_NOTFOUND;
    }

    unsigned char pDecrypteddata[16];

    card_t* usedCard;
    usedCard = (card_t*)nlist_remove(&card_list);
    rv = check_auth(usedCard->fd, uiKeyIndex, pFhe_Auth);
    if(rv != 0){
        nlist_insert(&card_list, &usedCard->node);
        return rv;
    }
    nlist_insert(&card_list, &usedCard->node);

	rv = Sm1_Index_EncDec(uiKeyIndex, pEncrypteddata, 16, 0, pDecrypteddata);

    rv = check_type(pDecrypteddata, INT64);

    if(rv == 0) {
        unsigned long long data = (unsigned long long)pDecrypteddata[8] << 56 |
		(unsigned long long)pDecrypteddata[9] << 48 |
		(unsigned long long)pDecrypteddata[10] << 40 |
		(unsigned long long)pDecrypteddata[11] << 32 |
		(unsigned long long)pDecrypteddata[12] << 24 |
		(unsigned long long)pDecrypteddata[13] << 16 |
		(unsigned long long)pDecrypteddata[14] << 8 |
		(unsigned long long)pDecrypteddata[15];
	    *pPlaindata = *((unsigned long long*)&data);
    }

	return rv;
}


int PDecF32(unsigned char* pEncrypteddata, unsigned int uiKeyIndex, char* pFhe_Auth, float* pPlaindata)
{
    int rv;
    rv = check_device_fd();
    if(rv < 0) {
        return NFHE_DEVICE_NOTFOUND;
    }

    unsigned char pDecrypteddata[16];

    card_t* usedCard;
    usedCard = (card_t*)nlist_remove(&card_list);
    rv = check_auth(usedCard->fd, uiKeyIndex, pFhe_Auth);
    if(rv != 0){
        nlist_insert(&card_list, &usedCard->node);
        return rv;
    }
    nlist_insert(&card_list, &usedCard->node);

	rv = Sm1_Index_EncDec(uiKeyIndex, pEncrypteddata, 16, 0, pDecrypteddata);

	rv = check_type(pDecrypteddata, F32);
    if(rv == 0) {
        unsigned long long data = (unsigned long long)pDecrypteddata[8] << 56 |
		(unsigned long long)pDecrypteddata[9] << 48 |
		(unsigned long long)pDecrypteddata[10] << 40 |
		(unsigned long long)pDecrypteddata[11] << 32 |
		(unsigned long long)pDecrypteddata[12] << 24 |
		(unsigned long long)pDecrypteddata[13] << 16 |
		(unsigned long long)pDecrypteddata[14] << 8 |
		(unsigned long long)pDecrypteddata[15];
	    *pPlaindata = *((float*)&data);
    }

	return rv;
}


int PDecF64(unsigned char* pEncrypteddata, unsigned int uiKeyIndex, char* pFhe_Auth, double* pPlaindata)
{
    int rv;
    rv = check_device_fd();
    if(rv < 0) {
        return NFHE_DEVICE_NOTFOUND;
    }

    unsigned char pDecrypteddata[16];

    card_t* usedCard;
    usedCard = (card_t*)nlist_remove(&card_list);
    rv = check_auth(usedCard->fd, uiKeyIndex, pFhe_Auth);
    if(rv != 0){
        nlist_insert(&card_list, &usedCard->node);
        return rv;
    }
    nlist_insert(&card_list, &usedCard->node);

	rv = Sm1_Index_EncDec(uiKeyIndex, pEncrypteddata, 16, 0, pDecrypteddata);

    rv = check_type(pDecrypteddata, D64);
    if(rv == 0) {
        unsigned long long data = (unsigned long long)pDecrypteddata[8] << 56 |
		(unsigned long long)pDecrypteddata[9] << 48 |
		(unsigned long long)pDecrypteddata[10] << 40 |
		(unsigned long long)pDecrypteddata[11] << 32 |
		(unsigned long long)pDecrypteddata[12] << 24 |
		(unsigned long long)pDecrypteddata[13] << 16 |
		(unsigned long long)pDecrypteddata[14] << 8 |
		(unsigned long long)pDecrypteddata[15];
	    *pPlaindata = *((double*)&data);
    }

    return rv;
}


int PDec(unsigned char* pEncrypteddata, unsigned int uiKeyIndex, char* pFhe_Auth, unsigned char* pPlaindata, unsigned char* pType)
{
    int rv;
    rv = check_device_fd();
    if(rv < 0) {
        return NFHE_DEVICE_NOTFOUND;
    }

    unsigned char pDecrypteddata[16];

    card_t* usedCard;
    usedCard = (card_t*)nlist_remove(&card_list);
    rv = check_auth(usedCard->fd, uiKeyIndex, pFhe_Auth);
    if(rv != 0){
        nlist_insert(&card_list, &usedCard->node);
        return rv;
    }
    nlist_insert(&card_list, &usedCard->node);

	rv = Sm1_Index_EncDec(uiKeyIndex, pEncrypteddata, 16, 0, pDecrypteddata);

    int extractedTypeValue = pDecrypteddata[3] * 10 + pDecrypteddata[7];
	switch(extractedTypeValue)
    {
        case INTS32:
            *pType = 0x00;
            break;
        case INT32:
            *pType = 0x01;
            break;
        case INTS64:
            *pType = 0x02;
            break;
        case INT64:
            *pType = 0x03;
            break;
        case F32:
            *pType = 0x04;
            break;
        case D64:
            *pType = 0x05;
            break;
        default:
            *pType = 0x00;
            break;
    }

    memcpy(pPlaindata, pDecrypteddata + 8, 8);

	return rv;
}


int	Compute_Dma(unsigned int uiKeyIdx1, unsigned int uiKeyIdx2, unsigned int uiKeyIdxR, int flag, unsigned char* inputData, unsigned int inputDataLength, unsigned char* outputData, unsigned int outputDataLength)
{
    sm1_ioctl_ctx ctx;
    int rv = 0;

    card_t* usedCard;

    while (inputDataLength > DMA_MAX_LENGTH) {
        // mode 1 加密 0 解密
        ctx.ssx_cmd = 1;
        ctx.inputLength = DMA_MAX_LENGTH;
        ctx.inbuf = malloc(ctx.inputLength + 1);
        memset(ctx.inbuf, 0, ctx.inputLength + 1);
        memcpy(ctx.inbuf, inputData, ctx.inputLength);

        ctx.outputLength = DMA_MAX_LENGTH/2;
        ctx.outbuf = malloc(ctx.outputLength + 1);
        memset(ctx.outbuf, 0, ctx.outputLength + 1);

        usedCard = (card_t*)nlist_remove(&card_list);
        write_usr_reg(usedCard->fd, 0x8300, ((uiKeyIdx1 & 0b11111111)) | ((uiKeyIdx2 & 0b11111111) << 8) | ((uiKeyIdxR & 0b11111111) << 16));
        write_usr_reg(usedCard->fd, 0x8310, inputDataLength / 2);
        write_usr_reg(usedCard->fd, 0x80FC, flag);
        rv = ioctl(usedCard->fd, IOCTL_NFHE_DMA_SM1, &ctx);
        nlist_insert(&card_list, &usedCard->node);

        if (rv < 0) {
            printf("IOCTL IOCTL_NFHE_DMA_SM1: failed\n");
            rv = NFHE_IOCTL_ERROR;
            break;
        } else {
            memcpy(outputData, ctx.outbuf, ctx.outputLength);
            inputData += ctx.inputLength;
            outputData += ctx.outputLength;
            inputDataLength -= ctx.inputLength;
            outputDataLength -= ctx.outputLength;
        }
        free(ctx.inbuf);
        free(ctx.outbuf);
    }

    if(inputDataLength > 0) {
        // mode 1 加密 0 解密
        ctx.ssx_cmd = 1;
        ctx.inputLength = inputDataLength;
        ctx.inbuf = malloc(ctx.inputLength + 1);
        memset(ctx.inbuf, 0, ctx.inputLength + 1);
        memcpy(ctx.inbuf, inputData, ctx.inputLength);

        ctx.outputLength = outputDataLength;
        ctx.outbuf = malloc(ctx.outputLength + 1);
        memset(ctx.outbuf, 0, ctx.outputLength + 1);

        usedCard = (card_t*)nlist_remove(&card_list);
        write_usr_reg(usedCard->fd, 0x8300, ((uiKeyIdx1 & 0b11111111)) | ((uiKeyIdx2 & 0b11111111) << 8) | ((uiKeyIdxR & 0b11111111) << 16));
        write_usr_reg(usedCard->fd, 0x8310, inputDataLength / 2);
        write_usr_reg(usedCard->fd, 0x80FC, flag);
        rv = ioctl(usedCard->fd, IOCTL_NFHE_DMA_SM1, &ctx);
        nlist_insert(&card_list, &usedCard->node);

        if (rv < 0) {
            printf("IOCTL IOCTL_NFHE_DMA_SM1: failed\n");
            rv = NFHE_IOCTL_ERROR;
        } else {
            memcpy(outputData, ctx.outbuf, ctx.outputLength);
            inputData += ctx.inputLength;
            outputData += ctx.outputLength;
            inputDataLength -= ctx.inputLength;
            outputDataLength -= ctx.outputLength;
        }
        free(ctx.inbuf);
        free(ctx.outbuf);
    }

    if(rv > 0) {
        rv = NFHE_OK;
    }

	return rv;
}


int	Compute_DmaEx(unsigned int nCount, unsigned int* pKeyIdx1, unsigned int* pKeyIdx2, unsigned int* pKeyIdxR, int flag, unsigned char* inputData, unsigned int inputDataLength, unsigned char* outputData, unsigned int outputDataLength)
{
    sm1_ioctl_ctx ctx;
    int rv = 0;

    card_t* usedCard;

    while (inputDataLength > DMA_MAX_LENGTH) {
        // mode 1 加密 0 解密
        ctx.ssx_cmd = 1;
        ctx.inputLength = DMA_MAX_LENGTH;
        ctx.inbuf = malloc(ctx.inputLength + 1);
        memset(ctx.inbuf, 0, ctx.inputLength + 1);
        memcpy(ctx.inbuf, inputData, ctx.inputLength);

        ctx.outputLength = DMA_MAX_LENGTH/2;
        ctx.outbuf = malloc(ctx.outputLength + 1);
        memset(ctx.outbuf, 0, ctx.outputLength + 1);

        usedCard = (card_t*)nlist_remove(&card_list);
        for(int i = 0; i < nCount; i++)
        {
            write_usr_reg(usedCard->fd, 0x8300, ((pKeyIdx1[i] & 0b11111111)) | ((pKeyIdx2[i] & 0b11111111) << 8) | ((pKeyIdxR[i] & 0b11111111) << 16));
        }
        write_usr_reg(usedCard->fd, 0x8310, inputDataLength/(2*nCount));
        write_usr_reg(usedCard->fd, 0x80FC, flag);
        rv = ioctl(usedCard->fd, IOCTL_NFHE_DMA_SM1, &ctx);
        nlist_insert(&card_list, &usedCard->node);

        if (rv < 0) {
            printf("IOCTL IOCTL_NFHE_DMA_SM1: failed\n");
            rv = NFHE_IOCTL_ERROR;
            break;
        } else {
            memcpy(outputData, ctx.outbuf, ctx.outputLength);
            inputData += ctx.inputLength;
            outputData += ctx.outputLength;
            inputDataLength -= ctx.inputLength;
            outputDataLength -= ctx.outputLength;
        }
        free(ctx.inbuf);
        free(ctx.outbuf);
    }

    if(inputDataLength > 0) {
        // mode 1 加密 0 解密
        ctx.ssx_cmd = 1;
        ctx.inputLength = inputDataLength;
        ctx.inbuf = malloc(ctx.inputLength + 1);
        memset(ctx.inbuf, 0, ctx.inputLength + 1);
        memcpy(ctx.inbuf, inputData, ctx.inputLength);

        ctx.outputLength = outputDataLength;
        ctx.outbuf = malloc(ctx.outputLength + 1);
        memset(ctx.outbuf, 0, ctx.outputLength + 1);

        usedCard = (card_t*)nlist_remove(&card_list);
        for(int i = 0; i < nCount; i++)
        {
            write_usr_reg(usedCard->fd, 0x8300, ((pKeyIdx1[i] & 0b11111111)) | ((pKeyIdx2[i] & 0b11111111) << 8) | ((pKeyIdxR[i] & 0b11111111) << 16));
        }
        write_usr_reg(usedCard->fd, 0x8310, inputDataLength/(2*nCount));
        write_usr_reg(usedCard->fd, 0x80FC, flag);
        rv = ioctl(usedCard->fd, IOCTL_NFHE_DMA_SM1, &ctx);
        nlist_insert(&card_list, &usedCard->node);

        if (rv < 0) {
            printf("IOCTL IOCTL_NFHE_DMA_SM1: failed\n");
            rv = NFHE_IOCTL_ERROR;
        } else {
            memcpy(outputData, ctx.outbuf, ctx.outputLength);
            inputData += ctx.inputLength;
            outputData += ctx.outputLength;
            inputDataLength -= ctx.inputLength;
            outputDataLength -= ctx.outputLength;
        }
        free(ctx.inbuf);
        free(ctx.outbuf);
    }

    if(rv > 0) {
        rv = NFHE_OK;
    }

	return rv;
}


int PTwoReturnOneEncData(unsigned int inputLen, unsigned int returnLen, char* pEncryptedOp1, unsigned int uiKeyIdx1, unsigned char* pEncryptedOp2, unsigned int uiKeyIdx2, unsigned char* pEncryptedResult, unsigned int uiKeyIdxR, int flag)
{
    int rv;
    rv = check_device_fd();
    if(rv < 0) {
        return NFHE_DEVICE_NOTFOUND;
    }

    unsigned char compare_plain[inputLen*2];
	memcpy(compare_plain, pEncryptedOp1, inputLen);
	memcpy(compare_plain + inputLen, pEncryptedOp2, inputLen);

	rv = Compute_Dma(uiKeyIdx1, uiKeyIdx2, uiKeyIdxR, flag, compare_plain, inputLen*2, pEncryptedResult, returnLen);

    return rv;
}


int PCompareReturnPlainData(unsigned int inputLen, unsigned int returnLen, unsigned char* pEncryptedOp1, unsigned int uiKeyIdx1, unsigned char* pEncryptedOp2, unsigned int uiKeyIdx2, int* pbResult, int flag)
{
    int rv;
    rv = check_device_fd();
    if(rv < 0) {
        return NFHE_DEVICE_NOTFOUND;
    }

    unsigned char compare_plain[inputLen*2];
	memcpy(compare_plain, pEncryptedOp1, inputLen);
	memcpy(compare_plain + inputLen, pEncryptedOp2, inputLen);

    unsigned char result_plain[returnLen];

	rv = Compute_Dma(uiKeyIdx1, uiKeyIdx2, uiKeyIdx2, flag, compare_plain, inputLen*2, result_plain, returnLen);

    unsigned long long data = (unsigned long long)result_plain[12] << 24 |
		(unsigned long long)result_plain[13] << 16 |
		(unsigned long long)result_plain[14] << 8 |
		(unsigned long long)result_plain[15];
	*pbResult = *((int*)&data);

    return rv;
}


int PAdd(unsigned char* pEncryptedOp1, unsigned int uiKeyIdx1, unsigned char* pEncryptedOp2, unsigned int uiKeyIdx2, unsigned char* pEncryptedResult, unsigned int uiKeyIdxR)
{
    return PTwoReturnOneEncData(16, 16, pEncryptedOp1, uiKeyIdx1, pEncryptedOp2, uiKeyIdx2, pEncryptedResult, uiKeyIdxR, ADD);
}

int PSub(unsigned char* pEncryptedOp1, unsigned int uiKeyIdx1, unsigned char* pEncryptedOp2, unsigned int uiKeyIdx2, unsigned char* pEncryptedResult, unsigned int uiKeyIdxR)
{
    return PTwoReturnOneEncData(16, 16, pEncryptedOp1, uiKeyIdx1, pEncryptedOp2, uiKeyIdx2, pEncryptedResult, uiKeyIdxR, SUB);
}

int PMul(unsigned char* pEncryptedOp1, unsigned int uiKeyIdx1, unsigned char* pEncryptedOp2, unsigned int uiKeyIdx2, unsigned char* pEncryptedResult, unsigned int uiKeyIdxR)
{
    return PTwoReturnOneEncData(16, 16, pEncryptedOp1, uiKeyIdx1, pEncryptedOp2, uiKeyIdx2, pEncryptedResult, uiKeyIdxR, MUL);
}

int PDiv(unsigned char* pEncryptedOp1, unsigned int uiKeyIdx1, unsigned char* pEncryptedOp2, unsigned int uiKeyIdx2, unsigned char* pEncryptedResult, unsigned int uiKeyIdxR)
{
    return PTwoReturnOneEncData(16, 16, pEncryptedOp1, uiKeyIdx1, pEncryptedOp2, uiKeyIdx2, pEncryptedResult, uiKeyIdxR, DIV);
}

int PComLT(unsigned char* pEncryptedOp1, unsigned int uiKeyIdx1, unsigned char* pEncryptedOp2, unsigned int uiKeyIdx2, unsigned char* pEncryptedResult, unsigned int uiKeyIdxR)
{
    return PTwoReturnOneEncData(16, 16, pEncryptedOp1, uiKeyIdx1, pEncryptedOp2, uiKeyIdx2, pEncryptedResult, uiKeyIdxR, COMPARE_LT);
}

int PComLTE(unsigned char* pEncryptedOp1, unsigned int uiKeyIdx1, unsigned char* pEncryptedOp2, unsigned int uiKeyIdx2, unsigned char* pEncryptedResult, unsigned int uiKeyIdxR)
{
    return PTwoReturnOneEncData(16, 16, pEncryptedOp1, uiKeyIdx1, pEncryptedOp2, uiKeyIdx2, pEncryptedResult, uiKeyIdxR, COMPARE_LTE);
}

int PComGT(unsigned char* pEncryptedOp1, unsigned int uiKeyIdx1, unsigned char* pEncryptedOp2, unsigned int uiKeyIdx2, unsigned char* pEncryptedResult, unsigned int uiKeyIdxR)
{
    return PTwoReturnOneEncData(16, 16, pEncryptedOp1, uiKeyIdx1, pEncryptedOp2, uiKeyIdx2, pEncryptedResult, uiKeyIdxR, COMPARE_GT);
}

int PComGTE(unsigned char* pEncryptedOp1, unsigned int uiKeyIdx1, unsigned char* pEncryptedOp2, unsigned int uiKeyIdx2, unsigned char* pEncryptedResult, unsigned int uiKeyIdxR)
{
    return PTwoReturnOneEncData(16, 16, pEncryptedOp1, uiKeyIdx1, pEncryptedOp2, uiKeyIdx2, pEncryptedResult, uiKeyIdxR, COMPARE_GTE);
}

int PComEQ(unsigned char* pEncryptedOp1, unsigned int uiKeyIdx1, unsigned char* pEncryptedOp2, unsigned int uiKeyIdx2, unsigned char* pEncryptedResult, unsigned int uiKeyIdxR)
{
    return PTwoReturnOneEncData(16, 16, pEncryptedOp1, uiKeyIdx1, pEncryptedOp2, uiKeyIdx2, pEncryptedResult, uiKeyIdxR, COMPARE_EQ);
}

int PComNE(unsigned char* pEncryptedOp1, unsigned int uiKeyIdx1, unsigned char* pEncryptedOp2, unsigned int uiKeyIdx2, unsigned char* pEncryptedResult, unsigned int uiKeyIdxR)
{
    return PTwoReturnOneEncData(16, 16, pEncryptedOp1, uiKeyIdx1, pEncryptedOp2, uiKeyIdx2, pEncryptedResult, uiKeyIdxR, COMPARE_NE);
}

int PLogAnd(unsigned char* pEncryptedOp1, unsigned int uiKeyIdx1, unsigned char* pEncryptedOp2, unsigned int uiKeyIdx2, unsigned char* pEncryptedResult, unsigned int uiKeyIdxR)
{
    return PTwoReturnOneEncData(16, 16, pEncryptedOp1, uiKeyIdx1, pEncryptedOp2, uiKeyIdx2, pEncryptedResult, uiKeyIdxR, LOG_AND);
}

int PLogOr(unsigned char* pEncryptedOp1, unsigned int uiKeyIdx1, unsigned char* pEncryptedOp2, unsigned int uiKeyIdx2, unsigned char* pEncryptedResult, unsigned int uiKeyIdxR)
{
    return PTwoReturnOneEncData(16, 16, pEncryptedOp1, uiKeyIdx1, pEncryptedOp2, uiKeyIdx2, pEncryptedResult, uiKeyIdxR, LOG_OR);
}

int PLogNot(unsigned char* pEncryptedOp1, unsigned int uiKeyIdx1, unsigned char* pEncryptedResult, unsigned int uiKeyIdxR)
{
    return PTwoReturnOneEncData(16, 16, pEncryptedOp1, uiKeyIdx1, pEncryptedOp1, uiKeyIdx1, pEncryptedResult, uiKeyIdxR, LOG_NOT);
}


int PComLTp(unsigned char* pEncryptedOp1, unsigned int uiKeyIdx1, unsigned char* pEncryptedOp2, unsigned int uiKeyIdx2, int* pbResult)
{
    return PCompareReturnPlainData(16, 16, pEncryptedOp1, uiKeyIdx1, pEncryptedOp2, uiKeyIdx2, pbResult, COMPARE_LTP);
}

int PComLTEp(unsigned char* pEncryptedOp1, unsigned int uiKeyIdx1, unsigned char* pEncryptedOp2, unsigned int uiKeyIdx2, int* pbResult)
{
    return PCompareReturnPlainData(16, 16, pEncryptedOp1, uiKeyIdx1, pEncryptedOp2, uiKeyIdx2, pbResult, COMPARE_LTEP);
}

int PComGTp(unsigned char* pEncryptedOp1, unsigned int uiKeyIdx1, unsigned char* pEncryptedOp2, unsigned int uiKeyIdx2, int* pbResult)
{
    return PCompareReturnPlainData(16, 16, pEncryptedOp1, uiKeyIdx1, pEncryptedOp2, uiKeyIdx2, pbResult, COMPARE_GTP);
}

int PComGTEp(unsigned char* pEncryptedOp1, unsigned int uiKeyIdx1, unsigned char* pEncryptedOp2, unsigned int uiKeyIdx2, int* pbResult)
{
    return PCompareReturnPlainData(16, 16, pEncryptedOp1, uiKeyIdx1, pEncryptedOp2, uiKeyIdx2, pbResult, COMPARE_GTEP);
}

int PComEQp(unsigned char* pEncryptedOp1, unsigned int uiKeyIdx1, unsigned char* pEncryptedOp2, unsigned int uiKeyIdx2, int* pbResult)
{
    return PCompareReturnPlainData(16, 16, pEncryptedOp1, uiKeyIdx1, pEncryptedOp2, uiKeyIdx2, pbResult, COMPARE_EQP);
}

int PComNEp(unsigned char* pEncryptedOp1, unsigned int uiKeyIdx1, unsigned char* pEncryptedOp2, unsigned int uiKeyIdx2, int* pbResult)
{
    return PCompareReturnPlainData(16, 16, pEncryptedOp1, uiKeyIdx1, pEncryptedOp2, uiKeyIdx2, pbResult, COMPARE_NEP);
}




int findpos(char* L) { //返回小数点的位置 如果没有小数点则返回L.length+1
	int i = 0;
	while ((i <= strlen(L)) && (L[i] != '.'))
		i++;
	return i;
}


int IsZero(char* a) {//该函数用于判断小数部分是不是为全零
	int i = 0;
	while ((a[i] == '0') && (i < strlen(a))) {
		i++;
		if (i == strlen(a))
			return 1;
	}
	return 0;
}


long long strto64(char* num) {
	//本函数实现小数部分的转换，s为小数最高位地址，len为小数部分的位数
	long long xiaoshu = 0;//返回值
	int count = 0, z = 0;
	while (z == 0 && count < 64) {
		int n = 0, temp = 0;
		for (int i = strlen(num) - 1; i >= 0; i--) {
			temp = (num[i] - '0') * 2 + n;  //n表示进位
			if (temp < 10) {
				num[i] = temp + '0';
				n = 0;
			}
			else {
				num[i] = temp - 10 + '0';
				n = 1;
			}
		}
		if (temp >= 10) {//如果最高位有进位，则输出增加
			long long yy = pow(2, 63 - count);
			xiaoshu += yy;
		}
		z = IsZero(num);
		count++;
	}//while
	return xiaoshu;
}


char* _64tostr(char* a, long long xiao) {//用于将64位小数转换为十进制字符串形式
	int k = 0;
	int d[64] = { 0 };
	for (int i = 0; i < 64; i++) {
		for (; k <= i; k++) {  //计算2^(-i-1)的值0.x，将计算结果0.x输出并将0.x的x保存在d[]中
			int r = 0;
			for (int j = 0; j <= k - 1; j++) {
				r = 10 * r + d[j];
				d[j] = r / 2;
				r = r % 2;
			}
			d[k] = 5;
		}
		long long temp = pow(2, 63 - i);//用于从最高位开始判断小数的某一位是否为1
		long long sig = xiao & temp;
		if (sig != 0) {
			int s = 0;
			for (int j = 63; j >= 0; j--) {//该循环将2^(-n)加到结果的字符串上
				a[j] = a[j] + d[j] + s;
				if (a[j] > '9') {
					a[j] = a[j] - 10;
					s = 1;
				}
				else {
					s = 0; //进位位归零
				}
			}
		}//if
	}//for
	return a;
}


// 大数 加密
int PEncBDecimal(char* szBDecimal, unsigned int uiKeyIndex, unsigned char* szEnc)
{
    int rv;
    rv = check_device_fd();
    if(rv < 0) {
        return NFHE_DEVICE_NOTFOUND;
    }

    char* L = (char*)malloc(strlen((char*)szBDecimal) + 1);
	memset(L, 0, strlen((char*)szBDecimal) + 1);
	memcpy(L, szBDecimal, strlen((char*)szBDecimal));
	int sign = 0;  //用于标记符号位
	if (L[0] == '-') {
		sign = 1;
		for (int j = 0; L[j] != '\0'; j++)
			L[j] = L[j + 1];
	}
	int pos = findpos(L);//记录小数点的位置
	long long zhengshu = 0, xiaoshu = 0;
	for (int i = 0; i < pos; i++) //提取出整数部分
		zhengshu += (long long)((L[pos - 1 - i] - '0') * pow(10, i));
	char* xiao = L + pos + 1;
	xiaoshu = strto64(xiao);
	if (sign == 1) {
		if (xiaoshu != 0)
		{
			zhengshu = 0 - zhengshu - 1;
			xiaoshu = 0 - xiaoshu;
		}
		else
		{
			zhengshu = 0 - zhengshu;
		}

	}

    unsigned char PlaindataWithType[32];
    setRandom(&PlaindataWithType[0]);
	PlaindataWithType[3] = 2;
    PlaindataWithType[4] = 64;
    PlaindataWithType[7] = 0;
    PlaindataWithType[8] = zhengshu >> 56 & 0b11111111;
    PlaindataWithType[9] = zhengshu >> 48 & 0b11111111;
    PlaindataWithType[10] = zhengshu >> 40 & 0b11111111;
    PlaindataWithType[11] = zhengshu >> 32 & 0b11111111;
    PlaindataWithType[12] = zhengshu >> 24 & 0b11111111;
    PlaindataWithType[13] = zhengshu >> 16 & 0b11111111;
    PlaindataWithType[14] = zhengshu >> 8 & 0b11111111;
    PlaindataWithType[15] = zhengshu & 0b11111111;
    PlaindataWithType[16] = xiaoshu >> 56 & 0b11111111;
    PlaindataWithType[17] = xiaoshu >> 48 & 0b11111111;
    PlaindataWithType[18] = xiaoshu >> 40 & 0b11111111;
    PlaindataWithType[19] = xiaoshu >> 32 & 0b11111111;
    PlaindataWithType[20] = xiaoshu >> 24 & 0b11111111;
    PlaindataWithType[21] = xiaoshu >> 16 & 0b11111111;
    PlaindataWithType[22] = xiaoshu >> 8 & 0b11111111;
    PlaindataWithType[23] = xiaoshu & 0b11111111;

	rv = Sm1_Index_EncDec(uiKeyIndex, PlaindataWithType, 32, 1, szEnc);

    if(L) {
        free(L);
    }

    return rv;
}

// 大数 解密
int PDecBDecimal(unsigned char* szEnc, unsigned int uiKeyIndex, char* pFhe_Auth, char* szBDecimal)
{
    int rv;
    rv = check_device_fd();
    if(rv < 0) {
        return NFHE_DEVICE_NOTFOUND;
    }

    unsigned char pDecrypteddata[32];

    card_t* usedCard;
    usedCard = (card_t*)nlist_remove(&card_list);
    rv = check_auth(usedCard->fd, uiKeyIndex, pFhe_Auth);
    if(rv != 0){
        nlist_insert(&card_list, &usedCard->node);
        return rv;
    }
    nlist_insert(&card_list, &usedCard->node);

	rv = Sm1_Index_EncDec(uiKeyIndex, szEnc, 32, 0, pDecrypteddata);

	rv = check_type(pDecrypteddata, BIGNUM);
    if(rv == 0) {
        unsigned long long data = (unsigned long long)pDecrypteddata[8] << 56 |
		(unsigned long long)pDecrypteddata[9] << 48 |
		(unsigned long long)pDecrypteddata[10] << 40 |
		(unsigned long long)pDecrypteddata[11] << 32 |
		(unsigned long long)pDecrypteddata[12] << 24 |
		(unsigned long long)pDecrypteddata[13] << 16 |
		(unsigned long long)pDecrypteddata[14] << 8 |
		(unsigned long long)pDecrypteddata[15];

        long long zhengshu = *((long long*)&data);

        data = (unsigned long long)pDecrypteddata[16] << 56 |
            (unsigned long long)pDecrypteddata[17] << 48 |
            (unsigned long long)pDecrypteddata[18] << 40 |
            (unsigned long long)pDecrypteddata[19] << 32 |
            (unsigned long long)pDecrypteddata[20] << 24 |
            (unsigned long long)pDecrypteddata[21] << 16 |
            (unsigned long long)pDecrypteddata[22] << 8 |
            (unsigned long long)pDecrypteddata[23];

        long long xiaoshu = *((long long*)&data);

        int sign = 0;  //用于标记符号位
        if (zhengshu < 0) {
            sign = 1;
            if (xiaoshu != 0)
            {
                zhengshu = 0 - zhengshu - 1;
                xiaoshu = 0 - xiaoshu;
            }
            else
                zhengshu = 0 - zhengshu;
        }

        char* str2 = (char*)malloc(65 * sizeof(char));
	    memset(str2, '0', 64);
        _64tostr(str2, xiaoshu);

        str2[20] = 0;
		str2[19] = 0;
		int nn = 0;
		if (str2[18] > '4') {
			nn = 1;
			for (int i = 17; i >= 0; i--) {
				str2[i] = str2[i] + nn;
				if (str2[i] > '9') {
					str2[i] = str2[i] - 10;
					nn = 1;
				}
				else {
					nn = 0;
					break;
				}
			}//小数部分进位
		}
		str2[18] = 0;

        zhengshu = zhengshu + nn;
        int size = 1; //用于表示输出字符串的长度
        char* str1 = (char*)malloc((size + 1) * sizeof(char));
        memset(str1, 0, size);
        if (zhengshu == 0) {
            str1[0] = '0';
            str1[1] = '\0';
        }
        while (zhengshu != 0) {//整数部分转换为字符串str1
            char* p = str1;
            str1 = (char*)malloc((size + 1) * sizeof(char));
            memset(str1, 0, size + 1);
            for (int i = size; i > 0; i--)
                str1[i] = p[i - 1];
            str1[0] = zhengshu % 10 + '0';
            size++;
            free(p);
            zhengshu /= 10;
        }

        int len = strlen(str2);
        // 从右向左找到第一个非零字符的位置
        int last_nonzero_index = -1;
        for (int i = len - 1; i >= 0; i--) {
            if (str2[i] != '0') {
                last_nonzero_index = i;
                break;
            }
        }

        // 如果没有找到非零字符，则保留一个零
        if (last_nonzero_index == -1) {
            str2[1] = '\0'; // 仅保留一个零
        }
        else {
            str2[last_nonzero_index + 1] = '\0'; // 删除非零字符后的部分
        }
        char* str3 = (char*)malloc((51) * sizeof(char));
        memset(str3, 0, 50 * sizeof(char));
        if (sign == 1) {
            memcpy(str3, "-", 1);
        }
        memcpy(str3 + (sign == 1), str1, strlen(str1));
        memcpy(str3 + (sign == 1) + strlen(str1), ".", 1);
        memcpy(str3 + (sign == 1) + strlen(str1) + 1, str2, strlen(str2));
        memcpy(szBDecimal, str3, strlen(str3));

        if(str1) {
            free(str1);
        }
            
        if(str2) {
            free(str2);
        }
	        
        if(str3) {
            free(str3);
        }
	        
    }

	return rv;
}

int PAddBd(unsigned char* szEncryptedOp1, unsigned int uiKeyIdx1, unsigned char* szEncryptedOp2, unsigned int uiKeyIdx2, unsigned char* szEncryptedResult, unsigned int uiKeyIdxR)
{
    return PTwoReturnOneEncData(32, 32, szEncryptedOp1, uiKeyIdx1, szEncryptedOp2, uiKeyIdx2, szEncryptedResult, uiKeyIdxR, ADD);
}

int PSubBd(unsigned char* szEncryptedOp1, unsigned int uiKeyIdx1, unsigned char* szEncryptedOp2, unsigned int uiKeyIdx2, unsigned char* szEncryptedResult, unsigned int uiKeyIdxR)
{
    return PTwoReturnOneEncData(32, 32, szEncryptedOp1, uiKeyIdx1, szEncryptedOp2, uiKeyIdx2, szEncryptedResult, uiKeyIdxR, SUB);
}

int PMulBd(unsigned char* szEncryptedOp1, unsigned int uiKeyIdx1, unsigned char* szEncryptedOp2, unsigned int uiKeyIdx2, unsigned char* szEncryptedResult, unsigned int uiKeyIdxR)
{
    return PTwoReturnOneEncData(32, 32, szEncryptedOp1, uiKeyIdx1, szEncryptedOp2, uiKeyIdx2, szEncryptedResult, uiKeyIdxR, MUL);
}

int PDivBd(unsigned char* szEncryptedOp1, unsigned int uiKeyIdx1, unsigned char* szEncryptedOp2, unsigned int uiKeyIdx2, unsigned char* szEncryptedResult, unsigned int uiKeyIdxR)
{
    return PTwoReturnOneEncData(32, 32, szEncryptedOp1, uiKeyIdx1, szEncryptedOp2, uiKeyIdx2, szEncryptedResult, uiKeyIdxR, DIV);
}

int PComLTBd(unsigned char* szEncryptedOp1, unsigned int uiKeyIdx1, unsigned char* szEncryptedOp2, unsigned int uiKeyIdx2, unsigned char* pEncrypteddata, unsigned int uiKeyIdxR)
{
    return PTwoReturnOneEncData(32, 16, szEncryptedOp1, uiKeyIdx1, szEncryptedOp2, uiKeyIdx2, pEncrypteddata, uiKeyIdxR, COMPARE_LT);
}

int PComLTEBd(unsigned char* szEncryptedOp1, unsigned int uiKeyIdx1, unsigned char* szEncryptedOp2, unsigned int uiKeyIdx2, unsigned char* pEncrypteddata, unsigned int uiKeyIdxR)
{
    return PTwoReturnOneEncData(32, 16, szEncryptedOp1, uiKeyIdx1, szEncryptedOp2, uiKeyIdx2, pEncrypteddata, uiKeyIdxR, COMPARE_LTE);
}

int PComGTBd(unsigned char* szEncryptedOp1, unsigned int uiKeyIdx1, unsigned char* szEncryptedOp2, unsigned int uiKeyIdx2, unsigned char* pEncrypteddata, unsigned int uiKeyIdxR)
{
    return PTwoReturnOneEncData(32, 16, szEncryptedOp1, uiKeyIdx1, szEncryptedOp2, uiKeyIdx2, pEncrypteddata, uiKeyIdxR, COMPARE_GT);
}

int PComGTEBd(unsigned char* szEncryptedOp1, unsigned int uiKeyIdx1, unsigned char* szEncryptedOp2, unsigned int uiKeyIdx2, unsigned char* pEncrypteddata, unsigned int uiKeyIdxR)
{
    return PTwoReturnOneEncData(32, 16, szEncryptedOp1, uiKeyIdx1, szEncryptedOp2, uiKeyIdx2, pEncrypteddata, uiKeyIdxR, COMPARE_GTE);
}

int PComEQBd(unsigned char* szEncryptedOp1, unsigned int uiKeyIdx1, unsigned char* szEncryptedOp2, unsigned int uiKeyIdx2, unsigned char* pEncrypteddata, unsigned int uiKeyIdxR)
{
    return PTwoReturnOneEncData(32, 16, szEncryptedOp1, uiKeyIdx1, szEncryptedOp2, uiKeyIdx2, pEncrypteddata, uiKeyIdxR, COMPARE_EQ);
}

int PComNEBd(unsigned char* szEncryptedOp1, unsigned int uiKeyIdx1, unsigned char* szEncryptedOp2, unsigned int uiKeyIdx2, unsigned char* pEncrypteddata, unsigned int uiKeyIdxR)
{
    return PTwoReturnOneEncData(32, 16, szEncryptedOp1, uiKeyIdx1, szEncryptedOp2, uiKeyIdx2, pEncrypteddata, uiKeyIdxR, COMPARE_NE);
}

int PComLTpBd(unsigned char* szEncryptedOp1, unsigned int uiKeyIdx1, unsigned char* szEncryptedOp2, unsigned int uiKeyIdx2, int* pbResult)
{
    return PCompareReturnPlainData(32, 16, szEncryptedOp1, uiKeyIdx1, szEncryptedOp2, uiKeyIdx2, pbResult, COMPARE_LTP);
}

int PComLTEpBd(unsigned char* szEncryptedOp1, unsigned int uiKeyIdx1, unsigned char* szEncryptedOp2, unsigned int uiKeyIdx2, int* pbResult)
{
    return PCompareReturnPlainData(32, 16, szEncryptedOp1, uiKeyIdx1, szEncryptedOp2, uiKeyIdx2, pbResult, COMPARE_LTEP);
}

int PComGTpBd(unsigned char* szEncryptedOp1, unsigned int uiKeyIdx1, unsigned char* szEncryptedOp2, unsigned int uiKeyIdx2, int* pbResult)
{
    return PCompareReturnPlainData(32, 16, szEncryptedOp1, uiKeyIdx1, szEncryptedOp2, uiKeyIdx2, pbResult, COMPARE_GTP);
}

int PComGTEpBd(unsigned char* szEncryptedOp1, unsigned int uiKeyIdx1, unsigned char* szEncryptedOp2, unsigned int uiKeyIdx2, int* pbResult)
{
    return PCompareReturnPlainData(32, 16, szEncryptedOp1, uiKeyIdx1, szEncryptedOp2, uiKeyIdx2, pbResult, COMPARE_GTEP);
}

int PComEQpBd(unsigned char* szEncryptedOp1, unsigned int uiKeyIdx1, unsigned char* szEncryptedOp2, unsigned int uiKeyIdx2, int* pbResult)
{
    return PCompareReturnPlainData(32, 16, szEncryptedOp1, uiKeyIdx1, szEncryptedOp2, uiKeyIdx2, pbResult, COMPARE_EQP);
}

int PComNEpBd(unsigned char* szEncryptedOp1, unsigned int uiKeyIdx1, unsigned char* szEncryptedOp2, unsigned int uiKeyIdx2, int* pbResult)
{
    return PCompareReturnPlainData(32, 16, szEncryptedOp1, uiKeyIdx1, szEncryptedOp2, uiKeyIdx2, pbResult, COMPARE_NEP);
}


unsigned int getEncStrLenFromPlainStr(char* pStr) {
    unsigned int uiDataLength = strlen((const char*)pStr);
	// 判断是否需要补充长度
	unsigned int additionalLength = 0;
	unsigned int totalLength = uiDataLength + 8;
	if (totalLength % 16 != 0) {
		additionalLength = 16 - (totalLength % 16);
		totalLength += additionalLength;
	}
    return totalLength + 4;
}


int PEncStr(char* pStr, unsigned int uiKeyIndex, unsigned char* pEncStr)
{
    int rv;
    rv = check_device_fd();
    if(rv < 0) {
        return NFHE_DEVICE_NOTFOUND;
    }

    unsigned int uiDataLength = strlen((const char*)pStr);
	// 判断是否需要补充长度
	unsigned int additionalLength = 0;
	unsigned int totalLength = uiDataLength + 8;
	if (totalLength % 16 != 0) {
		additionalLength = 16 - (totalLength % 16);
		totalLength += additionalLength;
	}

    // 创建新字符串(Bin)
	unsigned char* extendedBin = (unsigned char*)malloc(sizeof(unsigned char) * (1 + totalLength));
	memset(extendedBin, 0, sizeof(unsigned char) * (1 + totalLength));
    setRandom(&extendedBin[0]);
	memset(extendedBin + 3, 3, 1);
	memset(extendedBin + 7, 0, 1);
	memcpy(extendedBin + 8, pStr, uiDataLength);
	memset(extendedBin + 8 + uiDataLength, '\0', additionalLength);

    unsigned char pEncrypteddata[totalLength + 4];
    memset(pEncrypteddata, 0, sizeof(unsigned char) * (totalLength + 4));
    memcpy(pEncrypteddata, &totalLength, sizeof(unsigned int));

	rv = Sm1_Index_EncDec(uiKeyIndex, extendedBin, totalLength, 1, pEncrypteddata + 4);

    memcpy(pEncStr, pEncrypteddata, sizeof(unsigned char) * (totalLength + 4));

    return rv;
}


int PDecStr(unsigned char* pEncStr, unsigned int uiKeyIndex, char* pFhe_Auth, char* pStr)
{
    int rv;
    rv = check_device_fd();
    if(rv < 0) {
        return NFHE_DEVICE_NOTFOUND;
    }

    unsigned int totalLength = 0;
    memcpy(&totalLength, pEncStr, sizeof(unsigned int));

    unsigned char pDecrypteddata[totalLength];

    card_t* usedCard;
    usedCard = (card_t*)nlist_remove(&card_list);

    rv = check_auth(usedCard->fd, uiKeyIndex, pFhe_Auth);
    if(rv != 0){
        nlist_insert(&card_list, &usedCard->node);
        return rv;
    }
    nlist_insert(&card_list, &usedCard->node);

	rv = Sm1_Index_EncDec(uiKeyIndex, pEncStr + 4, totalLength, 0, pDecrypteddata);

	rv = check_type(pDecrypteddata, STR);
    if(rv == 0) {
        // strcpy(pStr, pDecrypteddata + 8);
        memcpy(pStr, pDecrypteddata + 8, totalLength - 8);
    }

	return rv;
}


int PCompareStrReturnPlainData(unsigned char* pEncStr1, unsigned int uiKeyIdx1, unsigned char* pEncStr2, unsigned int uiKeyIdx2, int* pResultPlain, int flag)
{
    int rv;
    rv = check_device_fd();
    if(rv < 0) {
        return NFHE_DEVICE_NOTFOUND;
    }

    unsigned int totalLength = 0;
    memcpy(&totalLength, pEncStr1, sizeof(unsigned int));

    unsigned char compare_plain_str[totalLength*2];
	memcpy(compare_plain_str, pEncStr1 + 4, totalLength);
	memcpy(compare_plain_str + totalLength, pEncStr2 + 4, totalLength);

    unsigned char result_plain[16];

	rv = Compute_Dma(uiKeyIdx1, uiKeyIdx2, uiKeyIdx2, flag, compare_plain_str, totalLength*2, result_plain, 16);

    unsigned long long data = (unsigned long long)result_plain[12] << 24 |
		(unsigned long long)result_plain[13] << 16 |
		(unsigned long long)result_plain[14] << 8 |
		(unsigned long long)result_plain[15];
	*pResultPlain = *((int*)&data);

    return rv;
}


int PTwoStrReturnOneEncData(unsigned char* pEncStr1, unsigned int uiKeyIdx1, unsigned char* pEncStr2, unsigned int uiKeyIdx2, unsigned char* pEncryptedResult, unsigned int uiKeyIdxR, int flag)
{
    int rv;
    rv = check_device_fd();
    if(rv < 0) {
        return NFHE_DEVICE_NOTFOUND;
    }

    unsigned int totalLength = 0;
    memcpy(&totalLength, pEncStr1, sizeof(unsigned int));

    unsigned char compare_plain_str[totalLength*2];
	memcpy(compare_plain_str, pEncStr1 + 4, totalLength);
	memcpy(compare_plain_str + totalLength, pEncStr2 + 4, totalLength);

	rv = Compute_Dma(uiKeyIdx1, uiKeyIdx2, uiKeyIdx2, flag, compare_plain_str, totalLength*2, pEncryptedResult, 16);

    return rv;
}

int PComStrLTp(unsigned char* pEncStr1, unsigned int uiKeyIndex1, unsigned char* pEncStr2, unsigned int uiKeyIndex2, int* pResultPlain)
{
    return PCompareStrReturnPlainData(pEncStr1, uiKeyIndex1, pEncStr2, uiKeyIndex2, pResultPlain, COMPARE_LTP);
}

int PComStrLTEp(unsigned char* pEncStr1, unsigned int uiKeyIndex1, unsigned char* pEncStr2, unsigned int uiKeyIndex2, int* pResultPlain)
{
    return PCompareStrReturnPlainData(pEncStr1, uiKeyIndex1, pEncStr2, uiKeyIndex2, pResultPlain, COMPARE_LTEP);
}

int PComStrGTp(unsigned char* pEncStr1, unsigned int uiKeyIndex1, unsigned char* pEncStr2, unsigned int uiKeyIndex2, int* pResultPlain)
{
    return PCompareStrReturnPlainData(pEncStr1, uiKeyIndex1, pEncStr2, uiKeyIndex2, pResultPlain, COMPARE_GTP);
}

int PComStrGTEp(unsigned char* pEncStr1, unsigned int uiKeyIndex1, unsigned char* pEncStr2, unsigned int uiKeyIndex2, int* pResultPlain)
{
    return PCompareStrReturnPlainData(pEncStr1, uiKeyIndex1, pEncStr2, uiKeyIndex2, pResultPlain, COMPARE_GTEP);
}

int PComStrEQp(unsigned char* pEncStr1, unsigned int uiKeyIndex1, unsigned char* pEncStr2, unsigned int uiKeyIndex2, int* pResultPlain)
{
    return PCompareStrReturnPlainData(pEncStr1, uiKeyIndex1, pEncStr2, uiKeyIndex2, pResultPlain, COMPARE_EQP);
}

int PComStrNEp(unsigned char* pEncStr1, unsigned int uiKeyIndex1, unsigned char* pEncStr2, unsigned int uiKeyIndex2, int* pResultPlain)
{
    return PCompareStrReturnPlainData(pEncStr1, uiKeyIndex1, pEncStr2, uiKeyIndex2, pResultPlain, COMPARE_NEP);
}


int PComStrLT(unsigned char* pEncStr1, unsigned int uiKeyIndex1, unsigned char* pEncStr2, unsigned int uiKeyIndex2, unsigned char* pEncryptedResult, unsigned int uiKeyIdxR)
{
    return PTwoStrReturnOneEncData(pEncStr1, uiKeyIndex1, pEncStr2, uiKeyIndex2, pEncryptedResult, uiKeyIdxR, COMPARE_LT);
}

int PComStrLTE(unsigned char* pEncStr1, unsigned int uiKeyIndex1, unsigned char* pEncStr2, unsigned int uiKeyIndex2, unsigned char* pEncryptedResult, unsigned int uiKeyIdxR)
{
    return PTwoStrReturnOneEncData(pEncStr1, uiKeyIndex1, pEncStr2, uiKeyIndex2, pEncryptedResult, uiKeyIdxR, COMPARE_LTE);
}

int PComStrGT(unsigned char* pEncStr1, unsigned int uiKeyIndex1, unsigned char* pEncStr2, unsigned int uiKeyIndex2, unsigned char* pEncryptedResult, unsigned int uiKeyIdxR)
{
    return PTwoStrReturnOneEncData(pEncStr1, uiKeyIndex1, pEncStr2, uiKeyIndex2, pEncryptedResult, uiKeyIdxR, COMPARE_GT);
}

int PComStrGTE(unsigned char* pEncStr1, unsigned int uiKeyIndex1, unsigned char* pEncStr2, unsigned int uiKeyIndex2, unsigned char* pEncryptedResult, unsigned int uiKeyIdxR)
{
    return PTwoStrReturnOneEncData(pEncStr1, uiKeyIndex1, pEncStr2, uiKeyIndex2, pEncryptedResult, uiKeyIdxR, COMPARE_GTE);
}

int PComStrEQ(unsigned char* pEncStr1, unsigned int uiKeyIndex1, unsigned char* pEncStr2, unsigned int uiKeyIndex2, unsigned char* pEncryptedResult, unsigned int uiKeyIdxR)
{
    return PTwoStrReturnOneEncData(pEncStr1, uiKeyIndex1, pEncStr2, uiKeyIndex2, pEncryptedResult, uiKeyIdxR, COMPARE_EQ);
}

int PComStrNE(unsigned char* pEncStr1, unsigned int uiKeyIndex1, unsigned char* pEncStr2, unsigned int uiKeyIndex2, unsigned char* pEncryptedResult, unsigned int uiKeyIdxR)
{
    return PTwoStrReturnOneEncData(pEncStr1, uiKeyIndex1, pEncStr2, uiKeyIndex2, pEncryptedResult, uiKeyIdxR, COMPARE_NE);
}

int PEncS32Ex(unsigned int nCount, int* pPlaindata, unsigned int* pKeyIndex, unsigned char* pEncrypteddata)
{
    int rv;
    rv = check_device_fd();
    if(rv < 0) {
        return NFHE_DEVICE_NOTFOUND;
    }

    unsigned char PlaindataWithType[16*nCount];
    unsigned char* p;
    long long data;
    for(int i = 0; i < nCount; i++)
    {
        data = (long long)pPlaindata[i];
        p = PlaindataWithType + 16*i;
        setRandom(&p[0]);
        *(p + 3) = 0;
        *(p + 7) = 0;
        *(p + 8) = data >> 56 & 0b11111111;
        *(p + 9) = data >> 48 & 0b11111111;
        *(p + 10) = data >> 40 & 0b11111111;
        *(p + 11) = data >> 32 & 0b11111111;
        *(p + 12) = data >> 24 & 0b11111111;
        *(p + 13) = data >> 16 & 0b11111111;
        *(p + 14) = data >> 8 & 0b11111111;
        *(p + 15) = data & 0b11111111;
    }
    
	rv = Sm1_Index_EncDecEx(nCount, pKeyIndex, PlaindataWithType, 16*nCount, 1, pEncrypteddata);

    return rv;
}


int PEnc32Ex(unsigned int nCount, unsigned int* pPlaindata, unsigned int* pKeyIndex, unsigned char* pEncrypteddata)
{
    int rv;
    rv = check_device_fd();
    if(rv < 0) {
        return NFHE_DEVICE_NOTFOUND;
    }

    unsigned char PlaindataWithType[16*nCount];
    unsigned char* p;
    unsigned long long data;
    for(int i = 0; i < nCount; i++)
    {
        data = (unsigned long long)pPlaindata[i];
        p = PlaindataWithType + 16*i;
        setRandom(&p[0]);
        *(p + 3) = 4;
        *(p + 7) = 0;
        *(p + 8) = data >> 56 & 0b11111111;
        *(p + 9) = data >> 48 & 0b11111111;
        *(p + 10) = data >> 40 & 0b11111111;
        *(p + 11) = data >> 32 & 0b11111111;
        *(p + 12) = data >> 24 & 0b11111111;
        *(p + 13) = data >> 16 & 0b11111111;
        *(p + 14) = data >> 8 & 0b11111111;
        *(p + 15) = data & 0b11111111;
    }
    
	rv = Sm1_Index_EncDecEx(nCount, pKeyIndex, PlaindataWithType, 16*nCount, 1, pEncrypteddata);

    return rv;
}


int PEncS64Ex(unsigned int nCount, long long* pPlaindata, unsigned int* pKeyIndex, unsigned char* pEncrypteddata)
{
    int rv;
    rv = check_device_fd();
    if(rv < 0) {
        return NFHE_DEVICE_NOTFOUND;
    }

    unsigned char PlaindataWithType[16*nCount];
    unsigned char* p;
    long long data;
    for(int i = 0; i < nCount; i++)
    {
        data = (long long)pPlaindata[i];
        p = PlaindataWithType + 16*i;
        setRandom(&p[0]);
        *(p + 3) = 0;
        *(p + 7) = 1;
        *(p + 8) = data >> 56 & 0b11111111;
        *(p + 9) = data >> 48 & 0b11111111;
        *(p + 10) = data >> 40 & 0b11111111;
        *(p + 11) = data >> 32 & 0b11111111;
        *(p + 12) = data >> 24 & 0b11111111;
        *(p + 13) = data >> 16 & 0b11111111;
        *(p + 14) = data >> 8 & 0b11111111;
        *(p + 15) = data & 0b11111111;
    }
    
	rv = Sm1_Index_EncDecEx(nCount, pKeyIndex, PlaindataWithType, 16*nCount, 1, pEncrypteddata);

    return rv;
}


int PEnc64Ex(unsigned int nCount, unsigned long long* pPlaindata, unsigned int* pKeyIndex, unsigned char* pEncrypteddata)
{
    int rv;
    rv = check_device_fd();
    if(rv < 0) {
        return NFHE_DEVICE_NOTFOUND;
    }

    unsigned char PlaindataWithType[16*nCount];
    unsigned char* p;
    unsigned long long data;
    for(int i = 0; i < nCount; i++)
    {
        data = (unsigned long long)pPlaindata[i];
        p = PlaindataWithType + 16*i;
        setRandom(&p[0]);
        *(p + 3) = 4;
        *(p + 7) = 1;
        *(p + 8) = data >> 56 & 0b11111111;
        *(p + 9) = data >> 48 & 0b11111111;
        *(p + 10) = data >> 40 & 0b11111111;
        *(p + 11) = data >> 32 & 0b11111111;
        *(p + 12) = data >> 24 & 0b11111111;
        *(p + 13) = data >> 16 & 0b11111111;
        *(p + 14) = data >> 8 & 0b11111111;
        *(p + 15) = data & 0b11111111;
    }

	rv = Sm1_Index_EncDecEx(nCount, pKeyIndex, PlaindataWithType, 16*nCount, 1, pEncrypteddata);

    return rv;
}


int PEncF32Ex(unsigned int nCount, float* pPlaindata, unsigned int* pKeyIndex, unsigned char* pEncrypteddata)
{
    int rv;
    rv = check_device_fd();
    if(rv < 0) {
        return NFHE_DEVICE_NOTFOUND;
    }

    unsigned char PlaindataWithType[16*nCount];
    unsigned char* p;
    union FloatToBytes {
		float f;
		unsigned char bytes[4];
	}converter;
    for(int i = 0; i < nCount; i++)
    {
        converter.f = pPlaindata[i];
        p = PlaindataWithType + 16*i;
        setRandom(&p[0]);
        *(p + 3) = 1;
        *(p + 7) = 0;
        *(p + 12) = converter.bytes[3] & 0b11111111;
        *(p + 13) = converter.bytes[2] & 0b11111111;
        *(p + 14) = converter.bytes[1] & 0b11111111;
        *(p + 15) = converter.bytes[0] & 0b11111111;
    }
    
	rv = Sm1_Index_EncDecEx(nCount, pKeyIndex, PlaindataWithType, 16*nCount, 1, pEncrypteddata);

    return rv;
}


int PEncF64Ex(unsigned int nCount, double* pPlaindata, unsigned int* pKeyIndex, unsigned char* pEncrypteddata)
{
    int rv;
    rv = check_device_fd();
    if(rv < 0) {
        return NFHE_DEVICE_NOTFOUND;
    }

    unsigned char PlaindataWithType[16*nCount];
    unsigned char* p;
    union DoubleToBytes {
		double d;
		unsigned char bytes[8];
	}converter;
    for(int i = 0; i < nCount; i++)
    {
        converter.d = pPlaindata[i];
        p = PlaindataWithType + 16*i;
        setRandom(&p[0]);
        *(p + 3) = 1;
        *(p + 7) = 1;
        *(p + 8) = converter.bytes[7] & 0b11111111;
        *(p + 9) = converter.bytes[6] & 0b11111111;
        *(p + 10) = converter.bytes[5] & 0b11111111;
        *(p + 11) = converter.bytes[4] & 0b11111111;
        *(p + 12) = converter.bytes[3] & 0b11111111;
        *(p + 13) = converter.bytes[2] & 0b11111111;
        *(p + 14) = converter.bytes[1] & 0b11111111;
        *(p + 15) = converter.bytes[0] & 0b11111111;
    }
    
	rv = Sm1_Index_EncDecEx(nCount, pKeyIndex, PlaindataWithType, 16*nCount, 1, pEncrypteddata);

    return rv;
}


int PDecS32Ex(unsigned int nCount, unsigned char* pEncrypteddata, unsigned int* pKeyIndex, char* pFhe_Auth, int* pPlaindata)
{
    int rv;
    rv = check_device_fd();
    if(rv < 0) {
        return NFHE_DEVICE_NOTFOUND;
    }

    unsigned char pDecrypteddata[16*nCount];

    card_t* usedCard;
    usedCard = (card_t*)nlist_remove(&card_list);
    rv = check_auth(usedCard->fd, pKeyIndex[0], pFhe_Auth);
    if(rv != 0){
        nlist_insert(&card_list, &usedCard->node);
        return rv;
    }
    nlist_insert(&card_list, &usedCard->node);

	rv = Sm1_Index_EncDecEx(nCount, pKeyIndex, pEncrypteddata, 16*nCount, 0, pDecrypteddata);

    for(int i = 0; i < nCount; i++)
    {
        rv = check_type(pDecrypteddata + i*16, INTS32);
        if(rv == 0) {
            unsigned long long data = (unsigned long long)pDecrypteddata[i*16 + 8] << 56 |
            (unsigned long long)pDecrypteddata[i*16 + 9] << 48 |
            (unsigned long long)pDecrypteddata[i*16 + 10] << 40 |
            (unsigned long long)pDecrypteddata[i*16 + 11] << 32 |
            (unsigned long long)pDecrypteddata[i*16 + 12] << 24 |
            (unsigned long long)pDecrypteddata[i*16 + 13] << 16 |
            (unsigned long long)pDecrypteddata[i*16 + 14] << 8 |
            (unsigned long long)pDecrypteddata[i*16 + 15];
            pPlaindata[i] = *((int*)&data);
        }
        else{
            break;
        }
    }

	return rv;
}


int PDec32Ex(unsigned int nCount, unsigned char* pEncrypteddata, unsigned int* pKeyIndex, char* pFhe_Auth, unsigned int* pPlaindata)
{
    int rv;
    rv = check_device_fd();
    if(rv < 0) {
        return NFHE_DEVICE_NOTFOUND;
    }

    unsigned char pDecrypteddata[16*nCount];

    card_t* usedCard;
    usedCard = (card_t*)nlist_remove(&card_list);
    rv = check_auth(usedCard->fd, pKeyIndex[0], pFhe_Auth);
    if(rv != 0){
        nlist_insert(&card_list, &usedCard->node);
        return rv;
    }
    nlist_insert(&card_list, &usedCard->node);

	rv = Sm1_Index_EncDecEx(nCount, pKeyIndex, pEncrypteddata, 16*nCount, 0, pDecrypteddata);
    
    for(int i = 0; i < nCount; i++)
    {
        rv = check_type(pDecrypteddata + i*16, INT32);
        if(rv == 0) {
            unsigned long long data = (unsigned long long)pDecrypteddata[i*16 + 8] << 56 |
            (unsigned long long)pDecrypteddata[i*16 + 9] << 48 |
            (unsigned long long)pDecrypteddata[i*16 + 10] << 40 |
            (unsigned long long)pDecrypteddata[i*16 + 11] << 32 |
            (unsigned long long)pDecrypteddata[i*16 + 12] << 24 |
            (unsigned long long)pDecrypteddata[i*16 + 13] << 16 |
            (unsigned long long)pDecrypteddata[i*16 + 14] << 8 |
            (unsigned long long)pDecrypteddata[i*16 + 15];
            pPlaindata[i] = *((unsigned int*)&data);
        }
        else{
            break;
        }
    }

	return rv;
}


int PDecS64Ex(unsigned int nCount, unsigned char* pEncrypteddata, unsigned int* pKeyIndex, char* pFhe_Auth, long long* pPlaindata)
{
    int rv;
    rv = check_device_fd();
    if(rv < 0) {
        return NFHE_DEVICE_NOTFOUND;
    }

    unsigned char pDecrypteddata[16*nCount];

    card_t* usedCard;
    usedCard = (card_t*)nlist_remove(&card_list);
    rv = check_auth(usedCard->fd, pKeyIndex[0], pFhe_Auth);
    if(rv != 0){
        nlist_insert(&card_list, &usedCard->node);
        return rv;
    }
    nlist_insert(&card_list, &usedCard->node);

	rv = Sm1_Index_EncDecEx(nCount, pKeyIndex, pEncrypteddata, 16*nCount, 0, pDecrypteddata);

    for(int i = 0; i < nCount; i++)
    {
        rv = check_type(pDecrypteddata + i*16, INTS64);
        if(rv == 0) {
            unsigned long long data = (unsigned long long)pDecrypteddata[i*16 + 8] << 56 |
            (unsigned long long)pDecrypteddata[i*16 + 9] << 48 |
            (unsigned long long)pDecrypteddata[i*16 + 10] << 40 |
            (unsigned long long)pDecrypteddata[i*16 + 11] << 32 |
            (unsigned long long)pDecrypteddata[i*16 + 12] << 24 |
            (unsigned long long)pDecrypteddata[i*16 + 13] << 16 |
            (unsigned long long)pDecrypteddata[i*16 + 14] << 8 |
            (unsigned long long)pDecrypteddata[i*16 + 15];
            pPlaindata[i] = *((long long*)&data);
        }
        else{
            break;
        }
    }

	return rv;
}


int PDec64Ex(unsigned int nCount, unsigned char* pEncrypteddata, unsigned int* pKeyIndex, char* pFhe_Auth, unsigned long long* pPlaindata)
{
    int rv;
    rv = check_device_fd();
    if(rv < 0) {
        return NFHE_DEVICE_NOTFOUND;
    }

    unsigned char pDecrypteddata[16*nCount];

    card_t* usedCard;
    usedCard = (card_t*)nlist_remove(&card_list);
    rv = check_auth(usedCard->fd, pKeyIndex[0], pFhe_Auth);
    if(rv != 0){
        nlist_insert(&card_list, &usedCard->node);
        return rv;
    }
    nlist_insert(&card_list, &usedCard->node);

	rv = Sm1_Index_EncDecEx(nCount, pKeyIndex, pEncrypteddata, 16*nCount, 0, pDecrypteddata);
    

    for(int i = 0; i < nCount; i++)
    {
        rv = check_type(pDecrypteddata + i*16, INT64);
        if(rv == 0) {
            unsigned long long data = (unsigned long long)pDecrypteddata[i*16 + 8] << 56 |
            (unsigned long long)pDecrypteddata[i*16 + 9] << 48 |
            (unsigned long long)pDecrypteddata[i*16 + 10] << 40 |
            (unsigned long long)pDecrypteddata[i*16 + 11] << 32 |
            (unsigned long long)pDecrypteddata[i*16 + 12] << 24 |
            (unsigned long long)pDecrypteddata[i*16 + 13] << 16 |
            (unsigned long long)pDecrypteddata[i*16 + 14] << 8 |
            (unsigned long long)pDecrypteddata[i*16 + 15];
            pPlaindata[i] = *((unsigned long long*)&data);
        }
        else{
            break;
        }
    }

	return rv;
}


int PDecF32Ex(unsigned int nCount, unsigned char* pEncrypteddata, unsigned int* pKeyIndex, char* pFhe_Auth, float* pPlaindata)
{
    int rv;
    rv = check_device_fd();
    if(rv < 0) {
        return NFHE_DEVICE_NOTFOUND;
    }

    unsigned char pDecrypteddata[16*nCount];

    card_t* usedCard;
    usedCard = (card_t*)nlist_remove(&card_list);
    rv = check_auth(usedCard->fd, pKeyIndex[0], pFhe_Auth);
    if(rv != 0){
        nlist_insert(&card_list, &usedCard->node);
        return rv;
    }
    nlist_insert(&card_list, &usedCard->node);

	rv = Sm1_Index_EncDecEx(nCount, pKeyIndex, pEncrypteddata, 16*nCount, 0, pDecrypteddata);
    

    for(int i = 0; i < nCount; i++)
    {
        rv = check_type(pDecrypteddata + i*16, F32);
        if(rv == 0) {
            unsigned long long data = (unsigned long long)pDecrypteddata[i*16 + 8] << 56 |
            (unsigned long long)pDecrypteddata[i*16 + 9] << 48 |
            (unsigned long long)pDecrypteddata[i*16 + 10] << 40 |
            (unsigned long long)pDecrypteddata[i*16 + 11] << 32 |
            (unsigned long long)pDecrypteddata[i*16 + 12] << 24 |
            (unsigned long long)pDecrypteddata[i*16 + 13] << 16 |
            (unsigned long long)pDecrypteddata[i*16 + 14] << 8 |
            (unsigned long long)pDecrypteddata[i*16 + 15];
            pPlaindata[i] = *((float*)&data);
        }
        else{
            break;
        }
    }

	return rv;
}


int PDecF64Ex(unsigned int nCount, unsigned char* pEncrypteddata, unsigned int* pKeyIndex, char* pFhe_Auth, double* pPlaindata)
{
    int rv;
    rv = check_device_fd();
    if(rv < 0) {
        return NFHE_DEVICE_NOTFOUND;
    }

    unsigned char pDecrypteddata[16*nCount];

    card_t* usedCard;
    usedCard = (card_t*)nlist_remove(&card_list);
    rv = check_auth(usedCard->fd, pKeyIndex[0], pFhe_Auth);
    if(rv != 0){
        nlist_insert(&card_list, &usedCard->node);
        return rv;
    }
    nlist_insert(&card_list, &usedCard->node);

	rv = Sm1_Index_EncDecEx(nCount, pKeyIndex, pEncrypteddata, 16*nCount, 0, pDecrypteddata);
    

    for(int i = 0; i < nCount; i++)
    {
        rv = check_type(pDecrypteddata + i*16, D64);
        if(rv == 0) {
            unsigned long long data = (unsigned long long)pDecrypteddata[i*16 + 8] << 56 |
            (unsigned long long)pDecrypteddata[i*16 + 9] << 48 |
            (unsigned long long)pDecrypteddata[i*16 + 10] << 40 |
            (unsigned long long)pDecrypteddata[i*16 + 11] << 32 |
            (unsigned long long)pDecrypteddata[i*16 + 12] << 24 |
            (unsigned long long)pDecrypteddata[i*16 + 13] << 16 |
            (unsigned long long)pDecrypteddata[i*16 + 14] << 8 |
            (unsigned long long)pDecrypteddata[i*16 + 15];
            pPlaindata[i] = *((double*)&data);
        }
        else{
            break;
        }
    }

	return rv;
}


int PDecEx(unsigned int nCount, unsigned char* pEncrypteddata, unsigned int* pKeyIndex, char* pFhe_Auth, unsigned char* pPlaindata, unsigned char* pType)
{
    int rv;
    rv = check_device_fd();
    if(rv < 0) {
        return NFHE_DEVICE_NOTFOUND;
    }

    unsigned char pDecrypteddata[16*nCount];

    card_t* usedCard;
    usedCard = (card_t*)nlist_remove(&card_list);
    rv = check_auth(usedCard->fd, pKeyIndex[0], pFhe_Auth);
    if(rv != 0){
        nlist_insert(&card_list, &usedCard->node);
        return rv;
    }
    nlist_insert(&card_list, &usedCard->node);

	rv = Sm1_Index_EncDecEx(nCount, pKeyIndex, pEncrypteddata, 16*nCount, 0, pDecrypteddata);
    

    for(int i = 0; i < nCount; i++)
    {
        int extractedTypeValue = pDecrypteddata[16*i + 3] * 10 + pDecrypteddata[16*i + 7];
        switch(extractedTypeValue)
        {
            case INTS32:
                pType[i] = 0x00;
                break;
            case INT32:
                pType[i] = 0x01;
                break;
            case INTS64:
                pType[i] = 0x02;
                break;
            case INT64:
                pType[i] = 0x03;
                break;
            case F32:
                pType[i] = 0x04;
                break;
            case D64:
                pType[i] = 0x05;
                break;
            default:
                pType[i] = 0x00;
                break;
        }
        memcpy(pPlaindata + 8*i, pDecrypteddata + 16*i + 8, 8);
    }

	return rv;
}


int PTwoReturnOneEncDataEx(unsigned int inputLen, unsigned int returnLen, unsigned int nCount, char* pEncryptedOp1, unsigned int* pKeyIdx1, unsigned char* pEncryptedOp2, unsigned int* pKeyIdx2, unsigned char* pEncryptedResult, unsigned int* pKeyIdxR, int flag)
{
    int rv;
    rv = check_device_fd();
    if(rv < 0) {
        return NFHE_DEVICE_NOTFOUND;
    }

    unsigned char compare_plain[inputLen*2*nCount];
    for(int i = 0; i < nCount; i++)
    {
        memcpy(compare_plain + inputLen*i*2, pEncryptedOp1 + inputLen*i, inputLen);
	    memcpy(compare_plain + inputLen*i*2 + inputLen, pEncryptedOp2 + inputLen*i, inputLen);
    }

	rv = Compute_DmaEx(nCount, pKeyIdx1, pKeyIdx2, pKeyIdxR, flag, compare_plain, inputLen*2*nCount, pEncryptedResult, returnLen*nCount);

    return rv;
}


int PCompareReturnPlainDataEx(unsigned int inputLen, unsigned int returnLen, unsigned int nCount, unsigned char* pEncryptedOp1, unsigned int* pKeyIdx1, unsigned char* pEncryptedOp2, unsigned int* pKeyIdx2, int* pbResult, int flag)
{
    int rv;
    rv = check_device_fd();
    if(rv < 0) {
        return NFHE_DEVICE_NOTFOUND;
    }

    unsigned char compare_plain[inputLen*2*nCount];
    for(int i = 0; i < nCount; i++)
    {
        memcpy(compare_plain + inputLen*i*2, pEncryptedOp1 + inputLen*i, inputLen);
	    memcpy(compare_plain + inputLen*i*2 + inputLen, pEncryptedOp2 + inputLen*i, inputLen);
    }

    unsigned char result_plain[returnLen*nCount];

	rv = Compute_DmaEx(nCount, pKeyIdx1, pKeyIdx2, pKeyIdx2, flag, compare_plain, inputLen*2*nCount, result_plain, returnLen*nCount);

    unsigned long long data;
    for(int i = 0; i < nCount; i++)
    {
        data = (unsigned long long)result_plain[16*i + 12] << 24 |
		(unsigned long long)result_plain[16*i + 13] << 16 |
		(unsigned long long)result_plain[16*i + 14] << 8 |
		(unsigned long long)result_plain[16*i + 15];
	    pbResult[i] = *((int*)&data);
    }
    
    return rv;
}


int PAddEx(unsigned int nCount, unsigned char* pEncryptedOp1, unsigned int* pKeyIdx1, unsigned char* pEncryptedOp2, unsigned int* pKeyIdx2, unsigned char* pEncryptedResult, unsigned int* pKeyIdxR)
{
    return PTwoReturnOneEncDataEx(16, 16, nCount, pEncryptedOp1, pKeyIdx1, pEncryptedOp2, pKeyIdx2, pEncryptedResult, pKeyIdxR, ADD);
}

int PSubEx(unsigned int nCount, unsigned char* pEncryptedOp1, unsigned int* pKeyIdx1, unsigned char* pEncryptedOp2, unsigned int* pKeyIdx2, unsigned char* pEncryptedResult, unsigned int* pKeyIdxR)
{
    return PTwoReturnOneEncDataEx(16, 16, nCount, pEncryptedOp1, pKeyIdx1, pEncryptedOp2, pKeyIdx2, pEncryptedResult, pKeyIdxR, SUB);
}

int PMulEx(unsigned int nCount, unsigned char* pEncryptedOp1, unsigned int* pKeyIdx1, unsigned char* pEncryptedOp2, unsigned int* pKeyIdx2, unsigned char* pEncryptedResult, unsigned int* pKeyIdxR)
{
    return PTwoReturnOneEncDataEx(16, 16, nCount, pEncryptedOp1, pKeyIdx1, pEncryptedOp2, pKeyIdx2, pEncryptedResult, pKeyIdxR, MUL);
}

int PDivEx(unsigned int nCount, unsigned char* pEncryptedOp1, unsigned int* pKeyIdx1, unsigned char* pEncryptedOp2, unsigned int* pKeyIdx2, unsigned char* pEncryptedResult, unsigned int* pKeyIdxR)
{
    return PTwoReturnOneEncDataEx(16, 16, nCount, pEncryptedOp1, pKeyIdx1, pEncryptedOp2, pKeyIdx2, pEncryptedResult, pKeyIdxR, DIV);
}


int PComLTExp(unsigned int nCount, unsigned char* pEncryptedOp1, unsigned int* pKeyIdx1, unsigned char* pEncryptedOp2, unsigned int* pKeyIdx2, int* pbResult)
{
    return PCompareReturnPlainDataEx(16, 16, nCount, pEncryptedOp1, pKeyIdx1, pEncryptedOp2, pKeyIdx2, pbResult, COMPARE_LTP);
}

int PComLTEExp(unsigned int nCount, unsigned char* pEncryptedOp1, unsigned int* pKeyIdx1, unsigned char* pEncryptedOp2, unsigned int* pKeyIdx2, int* pbResult)
{
    return PCompareReturnPlainDataEx(16, 16, nCount, pEncryptedOp1, pKeyIdx1, pEncryptedOp2, pKeyIdx2, pbResult, COMPARE_LTEP);
}

int PComGTExp(unsigned int nCount, unsigned char* pEncryptedOp1, unsigned int* pKeyIdx1, unsigned char* pEncryptedOp2, unsigned int* pKeyIdx2, int* pbResult)
{
    return PCompareReturnPlainDataEx(16, 16, nCount, pEncryptedOp1, pKeyIdx1, pEncryptedOp2, pKeyIdx2, pbResult, COMPARE_GTP);
}

int PComGTEExp(unsigned int nCount, unsigned char* pEncryptedOp1, unsigned int* pKeyIdx1, unsigned char* pEncryptedOp2, unsigned int* pKeyIdx2, int* pbResult)
{
    return PCompareReturnPlainDataEx(16, 16, nCount, pEncryptedOp1, pKeyIdx1, pEncryptedOp2, pKeyIdx2, pbResult, COMPARE_GTEP);
}

int PComEQExp(unsigned int nCount, unsigned char* pEncryptedOp1, unsigned int* pKeyIdx1, unsigned char* pEncryptedOp2, unsigned int* pKeyIdx2, int* pbResult)
{
    return PCompareReturnPlainDataEx(16, 16, nCount, pEncryptedOp1, pKeyIdx1, pEncryptedOp2, pKeyIdx2, pbResult, COMPARE_EQP);
}

int PComNEExp(unsigned int nCount, unsigned char* pEncryptedOp1, unsigned int* pKeyIdx1, unsigned char* pEncryptedOp2, unsigned int* pKeyIdx2, int* pbResult)
{
    return PCompareReturnPlainDataEx(16, 16, nCount, pEncryptedOp1, pKeyIdx1, pEncryptedOp2, pKeyIdx2, pbResult, COMPARE_NEP);
}


int PComLTEx(unsigned int nCount, unsigned char* pEncryptedOp1, unsigned int* pKeyIdx1, unsigned char* pEncryptedOp2, unsigned int* pKeyIdx2, unsigned char* pEncryptedResult, unsigned int* pKeyIdxR)
{
    return PTwoReturnOneEncDataEx(16, 16, nCount, pEncryptedOp1, pKeyIdx1, pEncryptedOp2, pKeyIdx2, pEncryptedResult, pKeyIdxR, COMPARE_LT);
}

int PComLTEEx(unsigned int nCount, unsigned char* pEncryptedOp1, unsigned int* pKeyIdx1, unsigned char* pEncryptedOp2, unsigned int* pKeyIdx2, unsigned char* pEncryptedResult, unsigned int* pKeyIdxR)
{
    return PTwoReturnOneEncDataEx(16, 16, nCount, pEncryptedOp1, pKeyIdx1, pEncryptedOp2, pKeyIdx2, pEncryptedResult, pKeyIdxR, COMPARE_LTE);
}

int PComGTEx(unsigned int nCount, unsigned char* pEncryptedOp1, unsigned int* pKeyIdx1, unsigned char* pEncryptedOp2, unsigned int* pKeyIdx2, unsigned char* pEncryptedResult, unsigned int* pKeyIdxR)
{
    return PTwoReturnOneEncDataEx(16, 16, nCount, pEncryptedOp1, pKeyIdx1, pEncryptedOp2, pKeyIdx2, pEncryptedResult, pKeyIdxR, COMPARE_GT);
}

int PComGTEEx(unsigned int nCount, unsigned char* pEncryptedOp1, unsigned int* pKeyIdx1, unsigned char* pEncryptedOp2, unsigned int* pKeyIdx2, unsigned char* pEncryptedResult, unsigned int* pKeyIdxR)
{
    return PTwoReturnOneEncDataEx(16, 16, nCount, pEncryptedOp1, pKeyIdx1, pEncryptedOp2, pKeyIdx2, pEncryptedResult, pKeyIdxR, COMPARE_GTE);
}

int PComEQEx(unsigned int nCount, unsigned char* pEncryptedOp1, unsigned int* pKeyIdx1, unsigned char* pEncryptedOp2, unsigned int* pKeyIdx2, unsigned char* pEncryptedResult, unsigned int* pKeyIdxR)
{
    return PTwoReturnOneEncDataEx(16, 16, nCount, pEncryptedOp1, pKeyIdx1, pEncryptedOp2, pKeyIdx2, pEncryptedResult, pKeyIdxR, COMPARE_EQ);
}

int PComNEEx(unsigned int nCount, unsigned char* pEncryptedOp1, unsigned int* pKeyIdx1, unsigned char* pEncryptedOp2, unsigned int* pKeyIdx2, unsigned char* pEncryptedResult, unsigned int* pKeyIdxR)
{
    return PTwoReturnOneEncDataEx(16, 16, nCount, pEncryptedOp1, pKeyIdx1, pEncryptedOp2, pKeyIdx2, pEncryptedResult, pKeyIdxR, COMPARE_NE);
}

int PLogAndEx(unsigned int nCount, unsigned char* pEncryptedOp1, unsigned int* pKeyIdx1, unsigned char* pEncryptedOp2, unsigned int* pKeyIdx2, unsigned char* pEncryptedResult, unsigned int* pKeyIdxR)
{
    return PTwoReturnOneEncDataEx(16, 16, nCount, pEncryptedOp1, pKeyIdx1, pEncryptedOp2, pKeyIdx2, pEncryptedResult, pKeyIdxR, LOG_AND);
}

int PLogOrEx(unsigned int nCount, unsigned char* pEncryptedOp1, unsigned int* pKeyIdx1, unsigned char* pEncryptedOp2, unsigned int* pKeyIdx2, unsigned char* pEncryptedResult, unsigned int* pKeyIdxR)
{
    return PTwoReturnOneEncDataEx(16, 16, nCount, pEncryptedOp1, pKeyIdx1, pEncryptedOp2, pKeyIdx2, pEncryptedResult, pKeyIdxR, LOG_OR);
}

int PLogNotEx(unsigned int nCount, unsigned char* pEncryptedOp1, unsigned int* pKeyIdx1, unsigned char* pEncryptedResult, unsigned int* pKeyIdxR)
{
    return PTwoReturnOneEncDataEx(16, 16, nCount, pEncryptedOp1, pKeyIdx1, pEncryptedOp1, pKeyIdx1, pEncryptedResult, pKeyIdxR, LOG_NOT);
}


int PEncBDecimalEx(unsigned int nCount, C_CHARPTR szBDecimal[], unsigned int* pKeyIndex, unsigned char* szEnc)
{
    int rv;
    rv = check_device_fd();
    if(rv < 0) {
        return NFHE_DEVICE_NOTFOUND;
    }

    unsigned char PlaindataWithType[32*nCount];
    for(int i = 0; i < nCount; i++)
    {
        char* L = (char*)malloc(strlen((char*)szBDecimal[i]) + 1);
        memset(L, 0, strlen((char*)szBDecimal[i]) + 1);
        memcpy(L, szBDecimal[i], strlen((char*)szBDecimal[i]));
        int sign = 0;  //用于标记符号位
        if (L[0] == '-') {
            sign = 1;
            for (int j = 0; L[j] != '\0'; j++) {
                L[j] = L[j + 1];
            }
        }
        int pos = findpos(L);//记录小数点的位置
        long long zhengshu = 0, xiaoshu = 0;
        for (int j = 0; j < pos; j++) { //提取出整数部分
            zhengshu += (long long)((L[pos - 1 - j] - '0') * pow(10, j));
        }
        char* xiao = L + pos + 1;
        xiaoshu = strto64(xiao);
        if (sign == 1) {
            if (xiaoshu != 0)
            {
                zhengshu = 0 - zhengshu - 1;
                xiaoshu = 0 - xiaoshu;
            }
            else
            {
                zhengshu = 0 - zhengshu;
            }

        }
        
        setRandom(&PlaindataWithType[32 * i + 0]);
        PlaindataWithType[32 * i + 3] = 2;
        PlaindataWithType[32 * i + 4] = 64;
        PlaindataWithType[32 * i + 7] = 0;
        PlaindataWithType[32 * i + 8] = zhengshu >> 56 & 0b11111111;
        PlaindataWithType[32 * i + 9] = zhengshu >> 48 & 0b11111111;
        PlaindataWithType[32 * i + 10] = zhengshu >> 40 & 0b11111111;
        PlaindataWithType[32 * i + 11] = zhengshu >> 32 & 0b11111111;
        PlaindataWithType[32 * i + 12] = zhengshu >> 24 & 0b11111111;
        PlaindataWithType[32 * i + 13] = zhengshu >> 16 & 0b11111111;
        PlaindataWithType[32 * i + 14] = zhengshu >> 8 & 0b11111111;
        PlaindataWithType[32 * i + 15] = zhengshu & 0b11111111;
        PlaindataWithType[32 * i + 16] = xiaoshu >> 56 & 0b11111111;
        PlaindataWithType[32 * i + 17] = xiaoshu >> 48 & 0b11111111;
        PlaindataWithType[32 * i + 18] = xiaoshu >> 40 & 0b11111111;
        PlaindataWithType[32 * i + 19] = xiaoshu >> 32 & 0b11111111;
        PlaindataWithType[32 * i + 20] = xiaoshu >> 24 & 0b11111111;
        PlaindataWithType[32 * i + 21] = xiaoshu >> 16 & 0b11111111;
        PlaindataWithType[32 * i + 22] = xiaoshu >> 8 & 0b11111111;
        PlaindataWithType[32 * i + 23] = xiaoshu & 0b11111111;

        if(L) {
            free(L);
        }
    }
    
	rv = Sm1_Index_EncDecEx(nCount, pKeyIndex, PlaindataWithType, 32*nCount, 1, szEnc);

    return rv;
}


int PDecBDecimalEx(unsigned int nCount, unsigned char* szEnc, unsigned int* pKeyIndex, char* pFhe_Auth, C_CHARPTR szBDecimal[])
{
    int rv;
    rv = check_device_fd();
    if(rv < 0) {
        return NFHE_DEVICE_NOTFOUND;
    }

    unsigned char pDecrypteddata[32*nCount];

    card_t* usedCard;
    usedCard = (card_t*)nlist_remove(&card_list);
    rv = check_auth(usedCard->fd, pKeyIndex[0], pFhe_Auth);
    if(rv != 0){
        nlist_insert(&card_list, &usedCard->node);
        return rv;
    }
    nlist_insert(&card_list, &usedCard->node);

	rv = Sm1_Index_EncDecEx(nCount, pKeyIndex, szEnc, 32*nCount, 0, pDecrypteddata);
    

    for(int i = 0; i < nCount; i++)
    {
        rv = check_type(pDecrypteddata + 32*i, BIGNUM);
    
        if(rv == 0) {
            unsigned long long data = (unsigned long long)pDecrypteddata[32*i + 8] << 56 |
            (unsigned long long)pDecrypteddata[32*i + 9] << 48 |
            (unsigned long long)pDecrypteddata[32*i + 10] << 40 |
            (unsigned long long)pDecrypteddata[32*i + 11] << 32 |
            (unsigned long long)pDecrypteddata[32*i + 12] << 24 |
            (unsigned long long)pDecrypteddata[32*i + 13] << 16 |
            (unsigned long long)pDecrypteddata[32*i + 14] << 8 |
            (unsigned long long)pDecrypteddata[32*i + 15];

            long long zhengshu = *((long long*)&data);

            data = (unsigned long long)pDecrypteddata[32*i + 16] << 56 |
                (unsigned long long)pDecrypteddata[32*i + 17] << 48 |
                (unsigned long long)pDecrypteddata[32*i + 18] << 40 |
                (unsigned long long)pDecrypteddata[32*i + 19] << 32 |
                (unsigned long long)pDecrypteddata[32*i + 20] << 24 |
                (unsigned long long)pDecrypteddata[32*i + 21] << 16 |
                (unsigned long long)pDecrypteddata[32*i + 22] << 8 |
                (unsigned long long)pDecrypteddata[32*i + 23];

            long long xiaoshu = *((long long*)&data);

            int sign = 0;  //用于标记符号位
            if (zhengshu < 0) {
                sign = 1;
                if (xiaoshu != 0)
                {
                    zhengshu = 0 - zhengshu - 1;
                    xiaoshu = 0 - xiaoshu;
                }
                else
                    zhengshu = 0 - zhengshu;
            }

            char* str2 = (char*)malloc(65 * sizeof(char));
            memset(str2, '0', 64);
            _64tostr(str2, xiaoshu);

            str2[20] = 0;
            str2[19] = 0;
            int nn = 0;
            if (str2[18] > '4') {
                nn = 1;
                for (int j = 17; j >= 0; j--) {
                    str2[j] = str2[j] + nn;
                    if (str2[j] > '9') {
                        str2[j] = str2[j] - 10;
                        nn = 1;
                    }
                    else {
                        nn = 0;
                        break;
                    }
                }//小数部分进位
            }
            str2[18] = 0;

            zhengshu = zhengshu + nn;
            int size = 1; //用于表示输出字符串的长度
            char* str1 = (char*)malloc((size + 1) * sizeof(char));
            memset(str1, 0, size);
            if (zhengshu == 0) {
                str1[0] = '0';
                str1[1] = '\0';
            }
            while (zhengshu != 0) {//整数部分转换为字符串str1
                char* p = str1;
                str1 = (char*)malloc((size + 1) * sizeof(char));
                memset(str1, 0, size + 1);
                for (int j = size; j > 0; j--) {
                    str1[j] = p[j - 1];
                }
                str1[0] = zhengshu % 10 + '0';
                size++;
                free(p);
                zhengshu /= 10;
            }

            int len = strlen(str2);
            // 从右向左找到第一个非零字符的位置
            int last_nonzero_index = -1;
            for (int j = len - 1; j >= 0; j--) {
                if (str2[j] != '0') {
                    last_nonzero_index = j;
                    break;
                }
            }

            // 如果没有找到非零字符，则保留一个零
            if (last_nonzero_index == -1) {
                str2[1] = '\0'; // 仅保留一个零
            }
            else {
                str2[last_nonzero_index + 1] = '\0'; // 删除非零字符后的部分
            }
            char* str3 = (char*)malloc((51) * sizeof(char));
            memset(str3, 0, 50 * sizeof(char));
            if (sign == 1) {
                memcpy(str3, "-", 1);
            }
            memcpy(str3 + (sign == 1), str1, strlen(str1));
            memcpy(str3 + (sign == 1) + strlen(str1), ".", 1);
            memcpy(str3 + (sign == 1) + strlen(str1) + 1, str2, strlen(str2));
            memcpy(szBDecimal[i], str3, strlen(str3));

            if(str1) {
                free(str1);
            }
                
            if(str2) {
                free(str2);
            }
                
            if(str3) {
                free(str3);
            }
        }
    }

	return rv;
}


int PAddBdEx(unsigned int nCount, unsigned char* szEncryptedOp1, unsigned int* pKeyIdx1, unsigned char* szEncryptedOp2, unsigned int* pKeyIdx2, unsigned char* szEncryptedResult, unsigned int* pKeyIdxR)
{
    return PTwoReturnOneEncDataEx(32, 32, nCount, szEncryptedOp1, pKeyIdx1, szEncryptedOp2, pKeyIdx2, szEncryptedResult, pKeyIdxR, ADD);
}

int PSubBdEx(unsigned int nCount, unsigned char* szEncryptedOp1, unsigned int* pKeyIdx1, unsigned char* szEncryptedOp2, unsigned int* pKeyIdx2, unsigned char* szEncryptedResult, unsigned int* pKeyIdxR)
{
    return PTwoReturnOneEncDataEx(32, 32, nCount, szEncryptedOp1, pKeyIdx1, szEncryptedOp2, pKeyIdx2, szEncryptedResult, pKeyIdxR, SUB);
}

int PMulBdEx(unsigned int nCount, unsigned char* szEncryptedOp1, unsigned int* pKeyIdx1, unsigned char* szEncryptedOp2, unsigned int* pKeyIdx2, unsigned char* szEncryptedResult, unsigned int* pKeyIdxR)
{
    return PTwoReturnOneEncDataEx(32, 32, nCount, szEncryptedOp1, pKeyIdx1, szEncryptedOp2, pKeyIdx2, szEncryptedResult, pKeyIdxR, MUL);
}

int PDivBdEx(unsigned int nCount, unsigned char* szEncryptedOp1, unsigned int* pKeyIdx1, unsigned char* szEncryptedOp2, unsigned int* pKeyIdx2, unsigned char* szEncryptedResult, unsigned int* pKeyIdxR)
{
    return PTwoReturnOneEncDataEx(32, 32, nCount, szEncryptedOp1, pKeyIdx1, szEncryptedOp2, pKeyIdx2, szEncryptedResult, pKeyIdxR, DIV);
}

int PComLTBdEx(unsigned int nCount, unsigned char* szEncryptedOp1, unsigned int* pKeyIdx1, unsigned char* szEncryptedOp2, unsigned int* pKeyIdx2, unsigned char* szEncryptedResult, unsigned int* pKeyIdxR)
{
    return PTwoReturnOneEncDataEx(32, 16, nCount, szEncryptedOp1, pKeyIdx1, szEncryptedOp2, pKeyIdx2, szEncryptedResult, pKeyIdxR, COMPARE_LT);
}

int PComLTEBdEx(unsigned int nCount, unsigned char* szEncryptedOp1, unsigned int* pKeyIdx1, unsigned char* szEncryptedOp2, unsigned int* pKeyIdx2, unsigned char* szEncryptedResult, unsigned int* pKeyIdxR)
{
    return PTwoReturnOneEncDataEx(32, 16, nCount, szEncryptedOp1, pKeyIdx1, szEncryptedOp2, pKeyIdx2, szEncryptedResult, pKeyIdxR, COMPARE_LTE);
}

int PComGTBdEx(unsigned int nCount, unsigned char* szEncryptedOp1, unsigned int* pKeyIdx1, unsigned char* szEncryptedOp2, unsigned int* pKeyIdx2, unsigned char* szEncryptedResult, unsigned int* pKeyIdxR)
{
    return PTwoReturnOneEncDataEx(32, 16, nCount, szEncryptedOp1, pKeyIdx1, szEncryptedOp2, pKeyIdx2, szEncryptedResult, pKeyIdxR, COMPARE_GT);
}

int PComGTEBdEx(unsigned int nCount, unsigned char* szEncryptedOp1, unsigned int* pKeyIdx1, unsigned char* szEncryptedOp2, unsigned int* pKeyIdx2, unsigned char* szEncryptedResult, unsigned int* pKeyIdxR)
{
    return PTwoReturnOneEncDataEx(32, 16, nCount, szEncryptedOp1, pKeyIdx1, szEncryptedOp2, pKeyIdx2, szEncryptedResult, pKeyIdxR, COMPARE_GTE);
}

int PComEQBdEx(unsigned int nCount, unsigned char* szEncryptedOp1, unsigned int* pKeyIdx1, unsigned char* szEncryptedOp2, unsigned int* pKeyIdx2, unsigned char* szEncryptedResult, unsigned int* pKeyIdxR)
{
    return PTwoReturnOneEncDataEx(32, 16, nCount, szEncryptedOp1, pKeyIdx1, szEncryptedOp2, pKeyIdx2, szEncryptedResult, pKeyIdxR, COMPARE_EQ);
}

int PComNEBdEx(unsigned int nCount, unsigned char* szEncryptedOp1, unsigned int* pKeyIdx1, unsigned char* szEncryptedOp2, unsigned int* pKeyIdx2, unsigned char* szEncryptedResult, unsigned int* pKeyIdxR)
{
    return PTwoReturnOneEncDataEx(32, 16, nCount, szEncryptedOp1, pKeyIdx1, szEncryptedOp2, pKeyIdx2, szEncryptedResult, pKeyIdxR, COMPARE_NE);
}


int PComLTBdExp(unsigned int nCount, unsigned char* szEncryptedOp1, unsigned int* pKeyIdx1, unsigned char* szEncryptedOp2, unsigned int* pKeyIdx2, int* pbResult)
{
    return PCompareReturnPlainDataEx(32, 16, nCount, szEncryptedOp1, pKeyIdx1, szEncryptedOp2, pKeyIdx2, pbResult, COMPARE_LTP);
}

int PComLTEBdExp(unsigned int nCount, unsigned char* szEncryptedOp1, unsigned int* pKeyIdx1, unsigned char* szEncryptedOp2, unsigned int* pKeyIdx2, int* pbResult)
{
    return PCompareReturnPlainDataEx(32, 16, nCount, szEncryptedOp1, pKeyIdx1, szEncryptedOp2, pKeyIdx2, pbResult, COMPARE_LTEP);
}

int PComGTBdExp(unsigned int nCount, unsigned char* szEncryptedOp1, unsigned int* pKeyIdx1, unsigned char* szEncryptedOp2, unsigned int* pKeyIdx2, int* pbResult)
{
    return PCompareReturnPlainDataEx(32, 16, nCount, szEncryptedOp1, pKeyIdx1, szEncryptedOp2, pKeyIdx2, pbResult, COMPARE_GTP);
}

int PComGTEBdExp(unsigned int nCount, unsigned char* szEncryptedOp1, unsigned int* pKeyIdx1, unsigned char* szEncryptedOp2, unsigned int* pKeyIdx2, int* pbResult)
{
    return PCompareReturnPlainDataEx(32, 16, nCount, szEncryptedOp1, pKeyIdx1, szEncryptedOp2, pKeyIdx2, pbResult, COMPARE_GTEP);
}

int PComEQBdExp(unsigned int nCount, unsigned char* szEncryptedOp1, unsigned int* pKeyIdx1, unsigned char* szEncryptedOp2, unsigned int* pKeyIdx2, int* pbResult)
{
    return PCompareReturnPlainDataEx(32, 16, nCount, szEncryptedOp1, pKeyIdx1, szEncryptedOp2, pKeyIdx2, pbResult, COMPARE_EQP);
}

int PComNEBdExp(unsigned int nCount, unsigned char* szEncryptedOp1, unsigned int* pKeyIdx1, unsigned char* szEncryptedOp2, unsigned int* pKeyIdx2, int* pbResult)
{
    return PCompareReturnPlainDataEx(32, 16, nCount, szEncryptedOp1, pKeyIdx1, szEncryptedOp2, pKeyIdx2, pbResult, COMPARE_NEP);
}


int SDF_HashInit(unsigned int fd, unsigned int uiAlgID, ECCrefPublicKey *pucPublicKey, unsigned char *pucID, unsigned int uiIDLength) {
    int rv;

    decd_ioctl_ctx data;
    if (uiAlgID == SGD_SM3_ID)
	{   
        data.inLen = 4 + 4 + sizeof(ECCrefPublicKey) + uiIDLength + 4;
        data.outLen = 8;
        int Command = SDF_HASHINIT;
        int len = data.inLen < data.outLen ? data.outLen : data.inLen;
        data.pDataBuf = malloc(len + 1);
        memset(data.pDataBuf, 0, len + 1);
        memcpy(data.pDataBuf, &Command, 4);
        memcpy(data.pDataBuf + 4, &uiAlgID, 4);
        memcpy(data.pDataBuf + 4 + 4, pucPublicKey, sizeof(ECCrefPublicKey));
        memcpy(data.pDataBuf + 4 + 4 + sizeof(ECCrefPublicKey), &uiIDLength, 4);
        memcpy(data.pDataBuf + 4 + 4 + sizeof(ECCrefPublicKey) + 4, pucID, uiIDLength);
	} else {
        data.inLen = 4 + 4;
        data.outLen = 8;
        int Command = SDF_HASHINIT;
        int len = data.inLen < data.outLen ? data.outLen : data.inLen;
        data.pDataBuf = malloc(len + 1);
        memset(data.pDataBuf, 0, len + 1);
        memcpy(data.pDataBuf, &Command, 4);
        memcpy(data.pDataBuf + 4, &uiAlgID, 4);
	}

    rv = ioctl(fd, IOCTL_DECD, &data);

    if (rv < 0) {
        printf("IOCTL IOCTL_DECD: failed\n");
        rv = NFHE_IOCTL_ERROR;
    } else {
        memcpy(&rv, data.pDataBuf, 4);
    }

    if(data.pDataBuf) {
        free(data.pDataBuf);
    }

    if (rv != 0){
        printf("SDF_HashInit: failed, rv: %x\n", rv);
        return rv;
    }

    return rv;
}


// SM3  
int NFHE_SM3(char* In, unsigned int InLength, char* Out) {
    int rv;
    rv = check_device_fd();
    if(rv < 0) {
        return NFHE_DEVICE_NOTFOUND;
    }

    unsigned int n = 0;
    n = InLength / 2;

    unsigned char pucDataByte[n];
	Str2Byte(pucDataByte, In);

    ECCrefPublicKey pPublicKey;

    card_t* usedCard;
    usedCard = (card_t*)nlist_remove(&card_list);

    rv = SDF_HashInit(usedCard->fd, SGD_SM3, &pPublicKey, NULL, 0);
    if(rv != 0) {
        nlist_insert(&card_list, &usedCard->node);
        return rv;
    }

    unsigned char *pMessage;
    pMessage = pucDataByte;
	while (n > FHE_SM3_INPUT_MAX) {
		if ((rv = SDF_HashUpdate(usedCard->fd, pMessage, FHE_SM3_INPUT_MAX)) != 0) {
            nlist_insert(&card_list, &usedCard->node);
			return rv;
		}
		pMessage += 1024;
		n -= 1024;
	}

    if (n > 0) {
        if ((rv = SDF_HashUpdate(usedCard->fd, pMessage, n)) != 0) {
            nlist_insert(&card_list, &usedCard->node);
			return rv;
		}
    }

    unsigned char pResult[32];
    unsigned int outlen;
    if ((rv = SDF_HashFinal(usedCard->fd, pResult, &outlen)) != 0) {
        nlist_insert(&card_list, &usedCard->node);
		return rv;
	}

    nlist_insert(&card_list, &usedCard->node);

    Byte2Str(Out, pResult, outlen);
	
    return rv;
}


int NFHE_SM3_ID(char* pucPublicKey, char* pucID, unsigned int IdLength, char* In, unsigned int InLength, char* Out) {

    int rv;
    rv = check_device_fd();
    if(rv < 0) {
        return NFHE_DEVICE_NOTFOUND;
    }

    unsigned int n, idLen;
    idLen = IdLength / 2;
	n = InLength / 2;

    unsigned char pucDataByte[n];
	Str2Byte(pucDataByte, In);

    
    ECCrefPublicKey pPublicKey;
    unsigned char pID[16];
    pPublicKey.bits = 256;
	Str2Byte(pPublicKey.x, pucPublicKey);
	Str2Byte(pID, pucID);

    card_t* usedCard;
    usedCard = (card_t*)nlist_remove(&card_list);

    if ((rv = SDF_HashInit(usedCard->fd, SGD_SM3_ID, &pPublicKey, pID, idLen)) != 0) {
        nlist_insert(&card_list, &usedCard->node);
		return rv;
	}

    unsigned char *pMessage;
    pMessage = pucDataByte;
	while (n > FHE_SM3_INPUT_MAX) {
		if ((rv = SDF_HashUpdate(usedCard->fd, pMessage, FHE_SM3_INPUT_MAX)) != 0) {
            nlist_insert(&card_list, &usedCard->node);
			return rv;
		}
		pMessage += 1024;
		n -= 1024;
	}

    if (n > 0) {
        if ((rv = SDF_HashUpdate(usedCard->fd, pMessage, n)) != 0) {
            nlist_insert(&card_list, &usedCard->node);
			return rv;
		}
    }

    unsigned char pResult[32];
    unsigned int outlen;
    if ((rv = SDF_HashFinal(usedCard->fd, pResult, &outlen)) != 0) {
        nlist_insert(&card_list, &usedCard->node);
		return rv;
	}
	
    nlist_insert(&card_list, &usedCard->node);

    Byte2Str(Out, pResult, outlen);

	return 0;
}


int NFHE_SM3_ID_Without_Key(char* pucID, unsigned int IdLength, char* In, unsigned int InLength, char* Out) {
    int rv;

    card_t* usedCard;
    usedCard = (card_t*)nlist_remove(&card_list);

    rv = NFHE_SM3_ID_Without_Key_INTERNAL(usedCard->fd, pucID, IdLength, In, InLength, Out);
	if (rv != 0) {
        nlist_insert(&card_list, &usedCard->node);
        return NFHE_SM3_ERROR;
    }

    nlist_insert(&card_list, &usedCard->node);

    return rv;
}